<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 7.3.0">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.ico">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.ico">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha256-wiz7ZSCn/btzhjKDQBms9Hx4sSeUYsDrTLg7roPstac=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.css" integrity="sha256-6cQIC71/iBIYXFK+0RHAvwmjwWzkWd+r7v/BX3/vZDc=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/themes/green/pace-theme-minimal.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pace/1.2.4/pace.min.js" integrity="sha256-gqd7YTjg/BtfqWSwsJOvndl0Bxc8gFImLEkXQT8+qj0=" crossorigin="anonymous"></script>

<script class="next-config" data-name="main" type="application/json">{"hostname":"sumumm.github.io","root":"/","images":"/images","scheme":"Gemini","darkmode":false,"version":"8.19.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":true,"style":"mac"},"fold":{"enable":true,"height":300},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":true,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>

    <meta name="description" content="本文主要是进程通信——信号的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:type" content="article">
<meta property="og:title" content="LV05-05-进程通信-03-信号">
<meta property="og:url" content="https://sumumm.github.io/post/8457f426.html">
<meta property="og:site_name" content="苏木">
<meta property="og:description" content="本文主要是进程通信——信号的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/LV05-05-%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-03-%E4%BF%A1%E5%8F%B7/img/image-20220607161056542.png">
<meta property="og:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/LV05-05-%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-03-%E4%BF%A1%E5%8F%B7/img/image-20220608163829684.png">
<meta property="article:published_time" content="2023-07-02T13:52:22.000Z">
<meta property="article:modified_time" content="2025-06-13T16:25:56.995Z">
<meta property="article:author" content="苏木">
<meta property="article:tag" content="LV05-操作系统">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/LV05-05-%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-03-%E4%BF%A1%E5%8F%B7/img/image-20220607161056542.png">


<link rel="canonical" href="https://sumumm.github.io/post/8457f426.html">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"https://sumumm.github.io/post/8457f426.html","path":"post/8457f426.html","title":"LV05-05-进程通信-03-信号"}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>LV05-05-进程通信-03-信号 | 苏木</title>
  








    <script src="/js/browser_tools_disable.js"></script>

  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>
<!-- hexo injector head_end start --><link rel="stylesheet" href="https://unpkg.com/hexo-next-tags-plus@latest/lib/tag_plus.css" media="defer" onload="this.media='all'"><!-- hexo injector head_end end --></head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <p class="site-title">苏木</p>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">我的学习之路</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>苏木的家</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类页<span class="badge">42</span></a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档页<span class="badge">673</span></a></li><li class="menu-item menu-item-flink"><a href="/flink/" rel="section"><i class="fa fa-link fa-fw"></i>友人帐</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于我</a></li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup"><div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off" maxlength="80"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close" role="button">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div class="search-result-container no-result">
  <div class="search-result-icon">
    <i class="fa fa-spinner fa-pulse fa-5x"></i>
  </div>
</div>

    </div>
  </div>

</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
            <div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%80%E3%80%81%E4%BF%A1%E5%8F%B7%E7%AE%80%E4%BB%8B"><span class="nav-text">一、信号简介</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E4%BF%A1%E5%8F%B7%E7%9A%84%E6%A6%82%E5%BF%B5"><span class="nav-text">1. 信号的概念</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E4%BF%A1%E5%8F%B7%E7%9A%84%E4%BA%A7%E7%94%9F"><span class="nav-text">2. 信号的产生</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-%E4%BF%A1%E5%8F%B7%E7%9A%84%E5%A4%84%E7%90%86%E6%96%B9%E5%BC%8F"><span class="nav-text">3. 信号的处理方式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-%E9%83%BD%E6%9C%89%E5%93%AA%E4%BA%9B%E4%BF%A1%E5%8F%B7"><span class="nav-text">4. 都有哪些信号</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5-%E5%B8%B8%E7%94%A8%E4%BF%A1%E5%8F%B7%E5%8F%8A%E5%90%AB%E4%B9%89"><span class="nav-text">5. 常用信号及含义</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#6-%E4%BF%A1%E5%8F%B7%E5%88%86%E7%B1%BB"><span class="nav-text">6. 信号分类</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#6-1-%E5%8F%AF%E9%9D%A0%E4%BF%A1%E5%8F%B7%E4%B8%8E%E4%B8%8D%E5%8F%AF%E9%9D%A0%E4%BF%A1%E5%8F%B7"><span class="nav-text">6.1 可靠信号与不可靠信号</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#6-2-%E5%AE%9E%E6%97%B6%E4%BF%A1%E5%8F%B7%E4%B8%8E%E9%9D%9E%E5%AE%9E%E6%97%B6%E4%BF%A1%E5%8F%B7"><span class="nav-text">6.2 实时信号与非实时信号</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#7-%E4%BF%A1%E5%8F%B7%E6%8F%8F%E8%BF%B0%E4%BF%A1%E6%81%AF"><span class="nav-text">7. 信号描述信息</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#7-1-strsignal"><span class="nav-text">7.1  strsignal() </span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#7-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">7.1.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#7-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">7.1.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#7-2-psignal"><span class="nav-text">7.2 psignal() </span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#7-2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">7.2.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#7-2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">7.2.2 使用实例</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%8C%E3%80%81%E8%BF%9B%E7%A8%8B%E5%AF%B9%E4%BF%A1%E5%8F%B7%E7%9A%84%E5%A4%84%E7%90%86"><span class="nav-text">二、进程对信号的处理</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E4%BF%A1%E5%8F%B7%E6%8D%95%E6%8D%89"><span class="nav-text">1. 信号捕捉</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-signal-%E5%87%BD%E6%95%B0"><span class="nav-text">2. signal() 函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.1 函数说明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B1"><span class="nav-text">2.2 使用实例1</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-3-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B2"><span class="nav-text">2.3 使用实例2</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-sigaction-%E5%87%BD%E6%95%B0"><span class="nav-text">3. sigaction() 函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">3.1 函数说明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-%E8%8E%B7%E5%8F%96%E4%BF%A1%E5%8F%B7%E6%90%BA%E5%B8%A6%E7%9A%84%E4%BF%A1%E6%81%AF"><span class="nav-text">3.2 获取信号携带的信息</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-3-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B1"><span class="nav-text">3.3 使用实例1</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-4-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B2"><span class="nav-text">3.4 使用实例2</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-%E5%AD%90%E8%BF%9B%E7%A8%8B%E5%9B%9E%E6%94%B6"><span class="nav-text">4. 子进程回收</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-1-signal-%E5%AE%9E%E7%8E%B0%E8%BF%9B%E7%A8%8B%E5%9B%9E%E6%94%B6"><span class="nav-text">4.1 signal() 实现进程回收</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-2-sigaction-%E5%AE%9E%E7%8E%B0%E8%BF%9B%E7%A8%8B%E5%9B%9E%E6%94%B6"><span class="nav-text">4.2 sigaction() 实现进程回收</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5-SIGABRT-%E4%BF%A1%E5%8F%B7"><span class="nav-text">5. SIGABRT 信号</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%89%E3%80%81%E5%90%91%E8%BF%9B%E7%A8%8B%E5%8F%91%E9%80%81%E4%BF%A1%E5%8F%B7"><span class="nav-text">三、向进程发送信号</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-kill"><span class="nav-text">1. kill() </span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">1.1 函数说明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">1.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-raise"><span class="nav-text">2. raise() </span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E-1"><span class="nav-text">2.1 函数说明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.2 使用实例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%9B%9B%E3%80%81%E5%AE%9A%E6%97%B6%E5%99%A8%E4%BA%A7%E7%94%9F%E4%BF%A1%E5%8F%B7"><span class="nav-text">四、定时器产生信号</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-alarm-%E5%87%BD%E6%95%B0"><span class="nav-text">1. alarm() 函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E-1"><span class="nav-text">1.1 函数说明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B1"><span class="nav-text">1.2 使用实例1</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B2"><span class="nav-text">1.3 使用实例2</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-ualarm-%E5%87%BD%E6%95%B0"><span class="nav-text">2. ualarm() 函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E-2"><span class="nav-text">2.1 函数说明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B-1"><span class="nav-text">2.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-setitimer-%E5%87%BD%E6%95%B0"><span class="nav-text">3. setitimer() 函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E-1"><span class="nav-text">3.1 函数说明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">3.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-getitimer-%E5%87%BD%E6%95%B0"><span class="nav-text">4. getitimer() 函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-1-getitimer"><span class="nav-text">4.1 getitimer() </span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">4.2 使用实例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%94%E3%80%81%E4%BF%A1%E5%8F%B7%E9%9B%86%E4%B8%8E%E4%BF%A1%E5%8F%B7%E9%98%BB%E5%A1%9E"><span class="nav-text">五、信号集与信号阻塞</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E7%9B%B8%E5%85%B3%E7%9A%84%E6%A6%82%E5%BF%B5"><span class="nav-text">1. 相关的概念</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-%E4%BF%A1%E5%8F%B7%E7%9A%84%E7%8A%B6%E6%80%81"><span class="nav-text">1.1 信号的状态</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-%E4%BF%A1%E5%8F%B7%E7%9A%84%E5%AD%98%E5%82%A8"><span class="nav-text">1.2 信号的存储</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-%E4%BF%A1%E5%8F%B7%E9%9B%86"><span class="nav-text">1.3 信号集</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E4%BF%A1%E5%8F%B7%E9%9B%86%E7%9B%B8%E5%85%B3%E6%93%8D%E4%BD%9C"><span class="nav-text">2. 信号集相关操作</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-%E5%88%9D%E5%A7%8B%E5%8C%96%E4%BF%A1%E5%8F%B7%E9%9B%86"><span class="nav-text">2.1 初始化信号集</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-1-sigemptyset"><span class="nav-text">2.1.1 sigemptyset() </span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#2-1-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.1.1.1 函数说明</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#2-1-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.1.1.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-2-sigfillset"><span class="nav-text">2.1.2 sigfillset() </span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#2-1-2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.1.2.1 函数说明</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#2-1-2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.1.2.2 使用实例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-%E5%90%91%E4%BF%A1%E5%8F%B7%E9%9B%86%E6%B7%BB%E5%8A%A0%E4%BF%A1%E5%8F%B7"><span class="nav-text">2.2 向信号集添加信号</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-2-1-sigaddset"><span class="nav-text">2.2.1 sigaddset() </span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#2-2-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.2.1.1 函数说明</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#2-2-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.2.1.2 使用实例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-3-%E4%BB%8E%E4%BF%A1%E5%8F%B7%E9%9B%86%E5%88%A0%E9%99%A4%E4%BF%A1%E5%8F%B7"><span class="nav-text">2.3 从信号集删除信号</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-3-1-sigdelset"><span class="nav-text">2.3.1 sigdelset() </span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#2-3-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.3.1.1 函数说明</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#2-3-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.3.1.2 使用实例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-4-%E6%B5%8B%E8%AF%95%E4%BF%A1%E5%8F%B7%E6%98%AF%E5%90%A6%E5%9C%A8%E4%BF%A1%E5%8F%B7%E9%9B%86"><span class="nav-text">2.4 测试信号是否在信号集</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-4-1-sigismember"><span class="nav-text">2.4.1 sigismember() </span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#2-4-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.4.1.1 函数说明</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#2-4-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.4.1.2 使用实例</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-%E9%98%BB%E5%A1%9E%E4%BF%A1%E5%8F%B7"><span class="nav-text">3. 阻塞信号</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-1-%E4%BF%A1%E5%8F%B7%E6%8E%A9%E7%A0%81"><span class="nav-text">3.1 信号掩码</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-sigprocmask-%E5%87%BD%E6%95%B0"><span class="nav-text">3.2 sigprocmask() 函数</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">3.2.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#3-2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">3.2.2 使用实例</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-3-%E8%8E%B7%E5%8F%96%E5%A4%84%E4%BA%8E%E9%98%BB%E5%A1%9E%E7%8A%B6%E6%80%81%E7%9A%84%E4%BF%A1%E5%8F%B7"><span class="nav-text">3.3 获取处于阻塞状态的信号</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#3-3-1-sigpending"><span class="nav-text">3.3.1 sigpending() </span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#3-3-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">3.3.1.1 函数说明</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#3-3-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">3.3.1.2 使用实例</span></a></li></ol></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%85%AD%E3%80%81%E9%98%BB%E5%A1%9E%E8%BF%9B%E7%A8%8B%E6%9D%A5%E7%AD%89%E5%BE%85%E4%BF%A1%E5%8F%B7"><span class="nav-text">六、阻塞进程来等待信号</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-pause-%E5%87%BD%E6%95%B0"><span class="nav-text">1. pause() 函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E-2"><span class="nav-text">1.1 函数说明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B-1"><span class="nav-text">1.2 使用实例</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-%E4%BF%A1%E5%8F%B7%E9%A9%B1%E5%8A%A8%E4%BB%BB%E5%8A%A1"><span class="nav-text">1.3 信号驱动任务</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-sigsuspend-%E5%87%BD%E6%95%B0"><span class="nav-text">2. sigsuspend() 函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E-3"><span class="nav-text">2.1 函数说明</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B-2"><span class="nav-text">2.2 使用实例</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%83%E3%80%81%E5%AE%9E%E6%97%B6%E4%BF%A1%E5%8F%B7"><span class="nav-text">七、实时信号</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E5%AE%9E%E6%97%B6%E4%BF%A1%E5%8F%B7%E7%9A%84%E4%BC%98%E5%8A%BF"><span class="nav-text">1. 实时信号的优势</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E6%97%B6%E4%BF%A1%E5%8F%B7"><span class="nav-text">2. 使用实时信号</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#2-1-sigqueue-%E5%87%BD%E6%95%B0"><span class="nav-text">2.1 sigqueue() 函数</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-1-%E5%87%BD%E6%95%B0%E8%AF%B4%E6%98%8E"><span class="nav-text">2.1.1 函数说明</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#2-1-2-%E4%BD%BF%E7%94%A8%E5%AE%9E%E4%BE%8B"><span class="nav-text">2.1.2 使用实例</span></a></li></ol></li></ol></li></ol></li></ol></div>
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="苏木"
      src="/images/avatar.jpg">
  <p class="site-author-name" itemprop="name">苏木</p>
  <div class="site-description" itemprop="description">莫道桑榆晚，为霞尚满天</div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">673</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">42</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
        <span class="site-state-item-count">43</span>
        <span class="site-state-item-name">标签</span>
      </div>
  </nav>
</div>
  <div class="links-of-author animated">
      <span class="links-of-author-item">
        <a href="https://github.com/sumumm" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;sumumm" rel="noopener me" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
  </div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner post posts-expand">


  


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://sumumm.github.io/post/8457f426.html">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.jpg">
      <meta itemprop="name" content="苏木">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="苏木">
      <meta itemprop="description" content="莫道桑榆晚，为霞尚满天">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="LV05-05-进程通信-03-信号 | 苏木">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          LV05-05-进程通信-03-信号
        </h1>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2023-07-02 21:52:22" itemprop="dateCreated datePublished" datetime="2023-07-02T21:52:22+08:00">2023-07-02</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/" itemprop="url" rel="index"><span itemprop="name">嵌入式开发</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/" itemprop="url" rel="index"><span itemprop="name">01HQ课程体系</span></a>
        </span>
          ，
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/" itemprop="url" rel="index"><span itemprop="name">LV05-操作系统</span></a>
        </span>
    </span>

  
    <span class="post-meta-break"></span>
    <span class="post-meta-item" title="本文字数">
      <span class="post-meta-item-icon">
        <i class="far fa-file-word"></i>
      </span>
      <span class="post-meta-item-text">本文字数：</span>
      <span>25k</span>
    </span>
    <span class="post-meta-item" title="阅读时长">
      <span class="post-meta-item-icon">
        <i class="far fa-clock"></i>
      </span>
      <span class="post-meta-item-text">阅读时长 &asymp;</span>
      <span>1:30</span>
    </span>
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody"><p>本文主要是进程通信——信号的相关笔记，若笔记中有错误或者不合适的地方，欢迎批评指正😃。</p>
<span id="more"></span>

<!-- Photo: https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/LV05-05-%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-03-%E4%BF%A1%E5%8F%B7/img/ -->

<details class="folding-tag" blue><summary> 点击查看使用工具及版本 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center" width=150px>Windows</td>        <td align="left">windows11</td>    </tr>    <tr>        <td align="center">Ubuntu</td>        <td align="left">Ubuntu16.04的64位版本</td>      </tr>    <tr>        <td align="center">VMware® Workstation 16 Pro</td>        <td align="left">16.2.3 build-19376536</td>      </tr>    <tr>        <td align="center">SecureCRT</td>        <td align="left">Version 8.7.2 (x64 build 2214)   -   正式版-2020年5月14日</td>      </tr>    <tr>        <td align="center">开发板</td>        <td align="left">正点原子 i.MX6ULL Linux阿尔法开发板</td>      </tr>    <tr>        <td align="center">uboot</td>        <td align="left">NXP官方提供的uboot，NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03)</td>      </tr>    <tr>        <td align="center">linux内核</td>        <td align="left">linux-4.15(NXP官方提供)</td>      </tr>    <tr>        <td align="center">STM32开发板</td>        <td align="left">正点原子战舰V3(STM32F103ZET6)</td>      </tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看本文参考资料 </summary>
              <div class='content'>
              <table>    <tr><td align="center">参考方向  </td><td align="center">参考原文</td></tr>    <tr><td align="left">---</td><td align="left"><a href="" target="_blank">--- <i class="fa fa-external-link-alt"></i> </a></td></tr></table>
              </div>
            </details>

<details class="folding-tag" blue><summary> 点击查看相关文件下载 </summary>
              <div class='content'>
              <table>    <tr>        <td align="center" width=150>---</td>        <td align="left"><a href="" target="_blank">---<i class="fa fa-external-link-alt"></i> </a></td>      </tr></table>
              </div>
            </details>


<h1 id="一、信号简介"><a href="#一、信号简介" class="headerlink" title="一、信号简介"></a><font size=3>一、信号简介</font></h1><h2 id="1-信号的概念"><a href="#1-信号的概念" class="headerlink" title="1. 信号的概念"></a><font size=3>1. 信号的概念</font></h2><p>信号是事件发生时对进程的通知机制，也可以把它称为<strong>软件中断</strong>。信号与硬件中断的相似之处在于能够打断程序当前执行的正常流程，其实是在软件层次上对中断机制的一种模拟。大多数情况下，是无法预测信号达到的准确时间，所以，信号提供了一种处理异步事件的方法。</p>
<p><strong>信号的目的</strong>都是用于通信的，当发生某种情况下，通过信号将情况告知相应的进程，从而达到同步、通信的目的。</p>
<p>另外<strong>信号是异步事件</strong>，而且是<strong>进程通信中唯一的异步通信机制</strong>，产生信号的事件对进程而言是随机出现的，进程无法预测该事件产生的准确时间，进程不能够通过简单地测试一个变量或使用系统调用来判断是否产生了一个信号，这就如同硬件中断事件，程序是无法得知中断事件产生的具体时间，只有当产生中断事件时，才会告知程序、然后打断当前程序的正常执行流程、跳转去执行中断服务函数，这就是异步处理方式。</p>
<h2 id="2-信号的产生"><a href="#2-信号的产生" class="headerlink" title="2. 信号的产生"></a><font size=3>2. 信号的产生</font></h2><ul>
<li>硬件发生异常</li>
</ul>
<p>就是硬件检测到错误条件并通知内核，随即再由内核发送相应的信号给相关进程。硬件检测到异常的例子包括执行一条异常的机器语言指令，诸如，除数为<code>0</code>、数组访问越界导致引用了无法访问的内存区域等，这些异常情况都会被硬件检测到，并通知内核、然后内核为该异常情况发生时正在运行的进程发送适当的信号以通知进程。</p>
<ul>
<li>在终端下输入了能够产生信号的特殊字符</li>
</ul>
<p>之前我们结束一个进程都是使用<code>Ctrl+C</code>，其实这样一个组合按键是产生了一个中断信号（<code>SIGINT</code>），通过这个信号可以终止在前台运行的进程；还有其他的组合键，例如按下<code>Ctrl + Z</code>组合按键可以产生暂停信号（<code>SIGCONT</code>），通过这个信号可以暂停当前前台运行的进程。</p>
<ul>
<li>进程调用<code>kill()</code>系统调用可将任意信号发送给另一个进程或进程组</li>
</ul>
<p>接收信号的进程和发送信号的进程的所有者必须相同，亦或者发送信号的进程的所有者是<code>root</code>超级用户。</p>
<ul>
<li>通过<code>kill</code>命令将信号发送给其它进程。</li>
</ul>
<p><code>kill</code>命令其实我们前边有使用过，通常我们会通过<code>kill</code>命令来杀死（终止）一个进程，例如在终端下执行<code>kill -9 xxx</code>来杀死<code>PID</code>为<code>xxx</code>的进程。<code>kill</code>命令其内部的实现原理便是通过<code>kill()</code>系统调用来完成的。</p>
<ul>
<li>发生软件事件</li>
</ul>
<p>也就是检测到某种软件条件已经发生。这里指的不是硬件产生的条件（如除数为<code>0</code>、引用无法访问的内存区域等），而是软件的触发条件、触发了某种软件条件（进程所设置的定时器已经超时、进程执行的<code>CPU</code>时间超限、进程的某个子进程退出等等情况）。</p>
<p><strong>其实进程同样也可以向自身发送信号</strong>，然而发送给进程的诸多信号中，大多数都是来自于内核。</p>
<h2 id="3-信号的处理方式"><a href="#3-信号的处理方式" class="headerlink" title="3. 信号的处理方式"></a><font size=3>3. 信号的处理方式</font></h2><p>信号通常是发送给对应的进程，当信号到达后，该进程需要做出相应的处理措施，通常进程会根据信号进行如下操作。</p>
<ul>
<li><strong>忽略信号</strong></li>
</ul>
<p>当信号到达进程后，该进程直接忽略，就好像是没有出现该信号，信号对该进程不会产生任何影响。事实上，大多数信号都可以使用这种方式进行处理，但有两种信号却决不能被忽略，它们是<code>SIGKILL</code>和<code>SIGSTOP</code>，这是因为它们向内核和超级用户提供了使进程终止或停止的可靠方法。另外，如果忽略某些由硬件异常产生的信号，则进程的运行行为是未定义的。</p>
<ul>
<li><strong>捕获信号</strong></li>
</ul>
<p>当信号到达进程后，执行预先绑定好的信号处理函数。为了做到这一点，要通知内核在某种信号发生时，执行用户自定义的处理函数，该处理函数中将会对该信号事件作出相应的处理，<code>Linux</code>系统提供了<code>signal()</code>系统调用可用于注册信号的处理函数。</p>
<ul>
<li><strong>执行系统默认操作</strong></li>
</ul>
<p>当信号到达进程后，进程不对该信号事件作出处理，而是交由系统进行处理，每一种信号都会有其对应的系统默认的处理方式。需要注意的是，对大多数信号来说，系统默认的处理方式就是终止该进程。</p>
<p>进程对信号的处理是可以通过函数来修改的，后边会详细学习。</p>
<h2 id="4-都有哪些信号"><a href="#4-都有哪些信号" class="headerlink" title="4. 都有哪些信号"></a><font size=3>4. 都有哪些信号</font></h2><p>上边说到了几个信号，那在我们的<code>Linux</code>系统中，有多少种信号呢？信号在本质上其实是<code>int</code>类型的数字编号，这些数字从<code>1</code>开始，定义在<code>.h</code>，文件中，我们可以使用如下命令查找该文件的位置：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">locate signum.h</span><br></pre></td></tr></table></figure>

<p>当然我们也可以通过终端直接打印出支持的信号，命令如下：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kill -l </span><br></pre></td></tr></table></figure>

<p>然后终端便会有如下信息显示：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"> 1) SIGHUP	     2) SIGINT	     3) SIGQUIT      4) SIGILL	     5) SIGTRAP</span><br><span class="line"> 6) SIGABRT	     7) SIGBUS	     8) SIGFPE	     9) SIGKILL	    10) SIGUSR1</span><br><span class="line">11) SIGSEGV	    12) SIGUSR2     13) SIGPIPE     14) SIGALRM	    15) SIGTERM</span><br><span class="line">16) SIGSTKFLT	17) SIGCHLD     18) SIGCONT     19) SIGSTOP	    20) SIGTSTP</span><br><span class="line">21) SIGTTIN	    22) SIGTTOU     23) SIGURG	    24) SIGXCPU	    25) SIGXFSZ</span><br><span class="line">26) SIGVTALRM	27) SIGPROF     28) SIGWINCH	29) SIGIO	    30) SIGPWR</span><br><span class="line">31) SIGSYS	    34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3</span><br><span class="line">38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8</span><br><span class="line">43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13</span><br><span class="line">48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12</span><br><span class="line">53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7</span><br><span class="line">58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2</span><br><span class="line">63) SIGRTMAX-1	64) SIGRTMAX</span><br></pre></td></tr></table></figure>

<p>当我们需要t通过终端发送某个信号给进程时，可以使用如下命令，大但是我们需要先知道接收信号的进程的<code>PID</code>，</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kill [-signal] &lt;pid&gt;</span><br></pre></td></tr></table></figure>

<p><code>signal</code>即为信号对应的<code>int</code>类型数字，例如，我们要杀死一个进程，使用的命令如下：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kill -9 &lt;pid&gt;</span><br></pre></td></tr></table></figure>

<h2 id="5-常用信号及含义"><a href="#5-常用信号及含义" class="headerlink" title="5. 常用信号及含义"></a><font size=3>5. 常用信号及含义</font></h2><p>上边那么多的信号，我们并不一定都用得上，常用的几个如下所示：</p>
<details class="folding-tag" blue><summary> 点击查看详细说明 </summary>
              <div class='content'>
              <p>【说明】</p><ul><li><code>term</code>表示终止进程</li><li><code>core</code>表示生成可用于调试的核心转储文件</li><li><code>ignore</code>表示忽略信号</li><li><code>continue</code>表示继续运行进程</li><li><code>pause</code>表示暂停进程</li></ul><table>    <tr><td align="center">编号</td><td align="left">信号名         </td><td align="center">默认操作     </td><td align="center">   含义</td></tr>                                                                      <tr><td align="center">1   </td><td align="left">SIGHUP	        </td><td align="left">term         </td><td align="left">在用户终端关闭时产生，通常是发给和该终端关联的会话内的所有进程</td></tr>	    <tr><td align="center">2   </td><td align="left">SIGINT         </td><td align="left">term         </td><td align="left">该信号在用户键入INTR字符(Ctrl-C)时产生，内核发送此信号到当前终端的所有前台进程</td></tr>    <tr><td align="center">3   </td><td align="left">SIGQUIT        </td><td align="left">term+core    </td><td align="left">该信号和SIGINT类似，但由QUIT字符(通常是Ctrl-\)来产生，进程如果陷入无限循环、或不再响应时，使用SIGQUIT信号就很合适</td></tr>    <tr><td align="center">4   </td><td align="left">SIGILL         </td><td align="left">term+core    </td><td align="left">该信号在一个进程企图执行一条非法指令时产生</td></tr>        <tr><td align="center">6   </td><td align="left">SIGABRT        </td><td align="left">term+core    </td><td align="left">当进程调用abort()系统调用时（进程异常终止），系统会向该进程发送SIGABRT信号</td></tr>                                                                                <tr><td align="center">7   </td><td align="left">SIGBUS         </td><td align="left">term+core    </td><td align="left">总线错误(bus error)信号，表示发生了某种内存访问错误</td></tr>                                                      <tr><td align="center">8   </td><td align="left">SIGFPE         </td><td align="left">term+core    </td><td align="left">该信号因特定类型的算术错误而产生，例如除以0</td></tr>                                                           <tr><td align="center">9   </td><td align="left">SIGKILL        </td><td align="left">term         </td><td align="left">该信号用来结束进程，并且不能被捕捉和忽略</td></tr>         <tr><td align="center">10  </td><td align="left">SIGUSR1        </td><td align="left">term         </td><td align="left">该信号保留给用户程序使用，内核绝不会为进程产生这些信号，在我们的程序中，可以使用这些信号来互通通知事件的发生，或是进程彼此同步操作</td></tr>         <tr><td align="center">11  </td><td align="left">SIGSEGV        </td><td align="left">term         </td><td align="left">该信号在非法访问内存时产生，如野指针、缓冲区溢出</td></tr>      <tr><td align="center">12  </td><td align="left">SIGUSR2        </td><td align="left">term         </td><td align="left">该信号保留给用户程序使用，内核绝不会为进程产生这些信号，在我们的程序中，可以使用这些信号来互通通知事件的发生，或是进程彼此同步操作</td></tr>       <tr><td align="center">13  </td><td align="left">SIGPIPE        </td><td align="left">term         </td><td align="left">当进程向已经关闭的管道、FIFO或套接字写入信息时，那么系统将发送该信号给进程</td></tr>       <tr><td align="center">14  </td><td align="left">SIGALRM        </td><td align="left">term         </td><td align="left">该信号用于通知进程定时器时间已到，与系统调用alarm()或setitimer()有关</td></tr>        <tr><td align="center">15  </td><td align="left">SIGTERM        </td><td align="left">term         </td><td align="left">终止进程的标准信号，也是kill命令所发送的默认信号。有时我们会直接使用"kill -9 xxx"显式向进程发送SIGKILL信号来终止进程，然而这一做法通常是错误的，精心设计的应用程序应该会捕获SIGTERM信号、并为其绑定一个处理函数，当该进程收到SIGTERM信号时，会在处理函数中清除临时文件以及释放其它资源，再而退出程序。如果直接使用SIGKILL信号终止进程，从而跳过了SIGTERM信号的处理函数，通常SIGKILL终止进程是不友好且暴力的方式，这种方式应该作为最后手段，应首先尝试使用SIGTERM，而将SIGKILL作为最后手段</td></tr>                                                              <tr><td align="center">17  </td><td align="left">SIGCHLD/SIGCLD </td><td align="left">ignore       </td><td align="left">当父进程的某一个子进程终止时，内核会向父进程发送该信号。当父进程的某一个子进程因收到信号而停止或恢复时，内核也可能向父进程发送该信号。注意这里说的停止并不是终止，我们可以理解为暂停</td></tr>    <tr><td align="center">18  </td><td align="left">SIGCONT        </td><td align="left">continue     </td><td align="left">该信号让进程进入运行态</td></tr>     <tr><td align="center">19  </td><td align="left">SIGSTOP        </td><td align="left">pause        </td><td align="left">该信号用于暂停进程，并且不能被捕捉和忽略</td></tr>          <tr><td align="center">20  </td><td align="left">SIGTSTP        </td><td align="left">pause        </td><td align="left">该信号用于暂停进程，用户可键入SUSP字符(通常是Ctrl-Z)发出这个信号，按下组合键后系统会将SIGTSTP信号发送给前台进程组中的每一个进程，使其暂停运行</td></tr>    <tr><td align="center">24  </td><td align="left">SIGXCPU        </td><td align="left">term+core    </td><td align="left">当进程的CPU时间超出对应的资源限制时，内核将发送此信号给该进程</td></tr>    <tr><td align="center">26  </td><td align="left">SIGVTALRM      </td><td align="left">term         </td><td align="left">应用程序调用setitimer()函数设置一个虚拟定时器，当定时器定时时间到时，内核将会发送该信号给进程</td></tr>      <tr><td align="center">28  </td><td align="left">SIGWINCH       </td><td align="left">ignore       </td><td align="left">在窗口环境中，当终端窗口尺寸发生变化时（例如用户手动调整了大小，应用程序调用ioctl()设置了大小等），系统会向前台进程组中的每一个进程发送该信号</td></tr>    <tr><td align="center">29  </td><td align="left">SIGPOLL/SIGIO  </td><td align="left">term/ignore  </td><td align="left">用于提示一个异步IO事件的发生，例如应用程序打开的文件描述符发生了I/O事件时，内核会向应用程序发送SIGIO信号</td></tr>    <tr><td align="center">31  </td><td align="left">SIGSYS         </td><td align="left">term+core    </td><td align="left">如果进程发起的系统调用有误，那么内核将发送该信号给对应的进程</td></tr>      </table>
              </div>
            </details>

<h2 id="6-信号分类"><a href="#6-信号分类" class="headerlink" title="6. 信号分类"></a><font size=3>6. 信号分类</font></h2><p><code>Linux</code>系统下可对信号从两个不同的角度进行分类，从<strong>可靠性方面将信号分为可靠信号与不可靠信号</strong>；而从<strong>实时性方面将信号分为实时信号与非实时信号</strong>。</p>
<h3 id="6-1-可靠信号与不可靠信号"><a href="#6-1-可靠信号与不可靠信号" class="headerlink" title="6.1 可靠信号与不可靠信号"></a><font size=3>6.1 可靠信号与不可靠信号</font></h3><p><code>Linux</code>信号机制基本上是从<code>UNIX</code>系统中继承过来的，早期<code>UNIX</code>系统中的信号机制比较简单和原始，后来在实践中暴露出一些问题，进程每次处理信号后，就将对信号的响应设置为系统默认操作。在某些情况下，将导致对信号的错误处理；因此，用户如果不希望这样的操作，那么就要在信号处理函数结尾再一次调用<code>signal()</code>，重新为该信号绑定相应的处理函数。</p>
<p>早期<code>UNIX</code>下的<strong>不可靠信号</strong>主要指的是进程可能对信号做出错误的反应以及信号可能丢失（处理信号时又来了新的信号，则导致信号丢失）。<br><code>Linux</code>支持不可靠信号，但是对不可靠信号机制做了改进：在调用完信号处理函数后，不必重新调用<code>signal()</code>。因此，<code>Linux</code>下的不可靠信号问题主要指的是信号可能丢失。在<code>Linux</code>系统下，信号值小于<code>SIGRTMIN（34）</code>（编号为<code>1~31</code>）的信号都是不可靠信号，这就是不可靠信号的来源。</p>
<p>随着时间的发展，实践证明，有必要对信号的原始机制加以改进和扩充，所以，后来出现的各种<code>UNIX</code>版本分别在这方面进行了研究，力图实现可靠信号。由于原来定义的信号已有许多应用，不好再做改动，最终只好又新增加了一些信号<code>SIGRTMIN~SIGRTMAX</code>，编号为<code>34~64</code>，并在一开始就把它们定义为<strong>可靠信号</strong>。可靠信号并没有一个具体对应的名字，而是使用了<code>SIGRTMIN+N</code>或<code>SIGRTMAX-N</code>的方式来表示。</p>
<p>可靠信号支持排队，不会丢失，同时，信号的发送和绑定也出现了新版本，信号发送函数<code>sigqueue()</code>及信号绑定函数<code>sigaction()</code>。</p>
<h3 id="6-2-实时信号与非实时信号"><a href="#6-2-实时信号与非实时信号" class="headerlink" title="6.2 实时信号与非实时信号"></a><font size=3>6.2 实时信号与非实时信号</font></h3><p>实时信号与非实时信号其实是从时间关系上进行的分类，与可靠信号与不可靠信号是相互对应的，<strong>非实时信号</strong>都不支持排队，都是不可靠信号，一般我们也把非实时信号（不可靠信号）称为<strong>标准信号</strong>；<strong>实时信号</strong>都支持排队，都是可靠信号。实时信号保证了发送的多个信号都能被接收，实时信号是<code>POSIX</code>标准的一部分，可用于应用进程。</p>
<h2 id="7-信号描述信息"><a href="#7-信号描述信息" class="headerlink" title="7. 信号描述信息"></a><font size=3>7. 信号描述信息</font></h2><p>在<code>Linux</code>下，每个信号都有一串与之相对应的字符串描述信息，用于对该信号进行相应的描述。这些字符串位于<code>sys_siglist</code>数组中，<code>sys_siglist</code>数组是一个<code>char *</code>类型的数组，数组中的每一个元素存放的是一个字符串指针，指向一个信号描述信息。</p>
<h3 id="7-1-strsignal"><a href="#7-1-strsignal" class="headerlink" title="7.1  strsignal() "></a><font size=3>7.1  strsignal() </font></h3><h4 id="7-1-1-函数说明"><a href="#7-1-1-函数说明" class="headerlink" title="7.1.1 函数说明"></a><font size=3>7.1.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man 3 strsignal</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">char</span> *<span class="title function_">strsignal</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">extern</span> <span class="type">const</span> <span class="type">char</span> * <span class="type">const</span> sys_siglist[];</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数可以用于获取信号的描述信息。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>sig</code>：<code>int</code>类型，需要显示详细信息的信号的宏（需要加上<code>&lt;signal.h&gt;</code>头文件）或者编号。</li>
</ul>
<p><strong>【返回值】</strong><code>char *</code>类型，返回执行信号描述信息字符串的指针；函数会对参数<code>sig</code>进行检查，若传入的<code>sig</code>无效，则会返回<code>Unknown signal</code>信息。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">strsignal(sig);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h4 id="7-1-2-使用实例"><a href="#7-1-2-使用实例" class="headerlink" title="7.1.2 使用实例"></a><font size=3>7.1.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;SIGINT Description: %s\n&quot;</span>, strsignal(SIGINT));</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;SIGQUIT Description: %s\n&quot;</span>, strsignal(SIGQUIT));</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;SIGBUS Description: %s\n&quot;</span>, strsignal(SIGBUS));</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">SIGINT Description: Interrupt</span><br><span class="line">SIGQUIT Description: Quit</span><br><span class="line">SIGBUS Description: Bus error</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h3 id="7-2-psignal"><a href="#7-2-psignal" class="headerlink" title="7.2 psignal() "></a><font size=3>7.2 psignal() </font></h3><h4 id="7-2-1-函数说明"><a href="#7-2-1-函数说明" class="headerlink" title="7.2.1 函数说明"></a><font size=3>7.2.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man 3 psignal</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">psignal</span><span class="params">(<span class="type">int</span> sig, <span class="type">const</span> <span class="type">char</span> *s)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数可以在标准错误（<code>stderr</code>）上输出信号描述信息，常用来输出信号的出错消息。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>sig</code>：<code>int</code>类型，需要显示详细信息的信号的宏（需要加上<code>&lt;signal.h&gt;</code>头文件）或者编号。</li>
<li><code>s</code>：<code>char *</code>类型，调用该函数时添加的一些提示信息，由<code>s</code>指定，所以整个输出信息由字符串<code>s</code>、冒号、空格、描述信号编号<code>sig</code>的字符串和尾随的换行符组成。</li>
</ul>
<p><strong>【返回值】</strong><code>none</code></p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">psignal(sig, <span class="string">&quot;Description&quot;</span>);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h4 id="7-2-2-使用实例"><a href="#7-2-2-使用实例" class="headerlink" title="7.2.2 使用实例"></a><font size=3>7.2.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	psignal(SIGINT, <span class="string">&quot;SIGINT&quot;</span>);</span><br><span class="line">	psignal(SIGQUIT, <span class="string">&quot;SIGQUIT&quot;</span>);</span><br><span class="line">	psignal(SIGBUS, <span class="string">&quot;SIGBUS&quot;</span>);</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">SIGINT: Interrupt</span><br><span class="line">SIGQUIT: Quit</span><br><span class="line">SIGBUS: Bus error</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h1 id="二、进程对信号的处理"><a href="#二、进程对信号的处理" class="headerlink" title="二、进程对信号的处理"></a><font size=3>二、进程对信号的处理</font></h1><h2 id="1-信号捕捉"><a href="#1-信号捕捉" class="headerlink" title="1. 信号捕捉"></a><font size=3>1. 信号捕捉</font></h2><p>如果信号的处理是自定义的，当信号递达时就调用某个用户自定义函数，这就是信号的捕捉。信号的捕捉流程大概如下图所示：</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/LV05-05-%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-03-%E4%BF%A1%E5%8F%B7/img/image-20220607161056542.png" alt="image-20220607161056542" style="zoom:50%;" />

<p>对于我们编程来说，可以看做是有两步：</p>
<ul>
<li><p>（1）定义新的信号的执行函数<code>handle</code>。</p>
</li>
<li><p>（2）使用<code>signal/sigaction</code> 函数，把自定义的<code>handle</code>和指定的信号相关联。</p>
</li>
</ul>
<p><strong>【注意事项】</strong>一般而言，将信号处理函数设计越简单越好，这就好比中断处理函数，越快越好，不要在处理函数中做大量消耗<code>CPU</code>时间的事情，设计的越简单也将降低引发信号竞争条件的风险。</p>
<h2 id="2-signal-函数"><a href="#2-signal-函数" class="headerlink" title="2. signal() 函数"></a><font size=3>2. signal() 函数</font></h2><h3 id="2-1-函数说明"><a href="#2-1-函数说明" class="headerlink" title="2.1 函数说明"></a><font size=3>2.1 函数说明</font></h3><p>在<code>linux</code>下可以使用<code>man signal</code>命令查看该函数的帮助手册，大概会有两种函数声明形式，但是其实是一样的，习惯上会使用形式一。</p>
<div class="tabs" id="tabname1"><ul class="nav-tabs"><li class="tab active"><a href="#tabname1-1">声明形式一</a></li><li class="tab"><a href="#tabname1-2">声明形式二</a></li></ul><div class="tab-content"><div class="tab-pane active" id="tabname1-1"><p>【说明】使用的命令为<code>man signal</code>或者<code>man 2 signal</code>查询到的系统调用的函数声明形式。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="title function_">void</span> <span class="params">(*<span class="type">sighandler_t</span>)</span><span class="params">(<span class="type">int</span>)</span>;</span><br><span class="line"><span class="type">sighandler_t</span> <span class="title function_">signal</span><span class="params">(<span class="type">int</span> signum, <span class="type">sighandler_t</span> handler)</span>;</span><br></pre></td></tr></table></figure></div><div class="tab-pane" id="tabname1-2"><p>【说明】使用<code>man 3 signal</code>查询到的库函数中的函数声明形式。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">void</span> (*signal(<span class="type">int</span> sig, <span class="type">void</span> (*func)(<span class="type">int</span>)))(<span class="type">int</span>);</span><br></pre></td></tr></table></figure></div></div></div>

<details class="folding-tag" blue><summary> 点击查看两种声明的关系 </summary>
              <div class='content'>
              <p>我们先来看声明形式二：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> (*signal(<span class="type">int</span> sig, <span class="type">void</span> (*func)(<span class="type">int</span>)))(<span class="type">int</span>);</span><br></pre></td></tr></table></figure><p>我们先拆分一下：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 注意一下函数指针的形式：&lt;数据类型&gt; (*&lt;函数指针名称&gt;) (&lt;参数说明列表&gt;);  */</span></span><br><span class="line"><span class="type">void</span> (  ) (<span class="type">int</span>)</span><br><span class="line">      |</span><br><span class="line">      *signal(<span class="type">int</span> sig,   )</span><br><span class="line">                       |</span><br><span class="line">                       <span class="type">void</span> (*func)(<span class="type">int</span>)</span><br><span class="line">                              </span><br></pre></td></tr></table></figure><ul><li>由于<code>()</code>的存在，<code>*func</code>是一个指针变量，后边的括号和<code>int</code>说明这个指针变量可以指向一个带有<code>int</code>形参的函数，前边的<code>void</code>说明这个函数指针指向的函数返回值为<code>void</code>类型，总的来说就是<code>void (*func)(int)</code>定义了一个函数指针变量<code>func</code>，它可以指向一个带有一个<code>int</code>参数的返回值为<code>void</code>类型的函数。可以指向的函数形式如下：</li></ul><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">functionName</span><span class="params">(<span class="type">int</span> arg)</span>;</span><br></pre></td></tr></table></figure><ul><li>再往上一层看，这就到了<code>signal</code>了，<code>*</code>的优先级是低于<code>()</code>的，所以<code>signal</code>先与后边的<code>(int sig, void (*func)(int))</code>相结合，说说明<code>signal</code>是一个函数，并且带有两个参数，一个是<code>int</code>类型的变量，一个是<code>void (*func)(int)</code>类型的函数指针变量。</li><li>再看<code>signal</code>前边的<code>*</code>表示这是一个指针变量，也就是说这个<code>signal</code>函数的返回值是一个指针变量。</li><li>接着就是最后的<code>(int)</code>，这表示，<code>signal</code>函数返回的指针变量可以指向一个带有<code>int</code>类型参数的函数。</li><li>最前边的<code>void</code>表示，<code>signal</code>函数返回的指针变量可以指向一个带有<code>int</code>类型参数且没有返回值的函数。</li></ul><p>总的来说，定义了一个指针函数<code>signal</code>，指针函数的返回值是一个函数指针，可以指向一个带有<code>int</code>类型参数且无返回值的函数；而<code>signal</code>含有两个参数，一个是普通的整型变量，另一个是函数指针类型，可以指向带有一个<code>int</code>类型且无返回值的函数。</p><p>经过分析，会发现，<code>signal</code>的返回值和<code>signal</code>函数第二个参数的类型是一样的，他们都是函数指针，都可以指向一个带有一个<code>int</code>类型参数的没有返回值的函数。前边我们使用<code>typedef</code>简化过这样的定义的，所以这里，我们可以这样也做一个简化：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="title function_">void</span> <span class="params">(*pfunc)</span><span class="params">(<span class="type">int</span>)</span></span><br></pre></td></tr></table></figure><p>这样，上边的函数就可以写为：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pfunc <span class="title function_">signal</span><span class="params">(<span class="type">int</span> sig, pfunc)</span>;<span class="comment">/* 需要注意的是，声明只需要类型即可，不一定需要写出形参*/</span></span><br></pre></td></tr></table></figure><p>这样是不是就跟前边形式一很像了呢？我们把<code>pfunc</code>换成<code>sighandler_t</code>其实就得到了形式一的声明，这完全是可以的，毕竟指针变量名只要符合标识规则即可</p>
              </div>
            </details>

<p><strong>【函数说明】</strong>该函数可以修改进程对信号的处理方式，可将信号的处理方式设置为捕获信号、忽略信号以及系统默认操作。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>signum</code>：<code>int</code>类型，此参数指定需要进行设置的信号，可使用信号名（宏）或信号的数字编号，不过一般建议使用信号名。</li>
<li><code>handler</code>：<code>sighandler_t</code>类型，是一个函数指针，指向信号对应的信号处理函数，当进程接收到信号后会自动执行该处理函数；也可以指向几个预定义函数。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 handler 可指向的预定义函数 </summary>
              <div class='content'>
              <table>    <tr><td align="center" width=150px>SIG_DFL</td><td align="left">表示设置为系统默认操作</td></tr>    <tr><td align="center" width=150px>SIG_IGN</td><td align="left">表示设置为忽视信号</td></tr></table>
              </div>
            </details>

<p><strong>【返回值】</strong><code>sighandler_t</code>类型，是一个函数指针，成功情况下的返回值则是指向在此之前的信号处理函数；如果出错则返回<code>SIG_ERR</code>，并会设置<code>errno</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="title function_">void</span> <span class="params">(*<span class="type">sighandler_t</span>)</span><span class="params">(<span class="type">int</span>)</span>;<span class="comment">/* 不需要使用sighandler_t定义变量时，好像不写也可以 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigintHandle</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 需要函数返回值 */</span></span><br><span class="line"><span class="type">sighandler_t</span> oldact;</span><br><span class="line">oldact = signal(SIGINT, sigintHandle);</span><br><span class="line"><span class="comment">/* 或者不需要函数返回值 */</span></span><br><span class="line">signal(SIGINT, sigintHandle);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong>信号处理函数声明一般如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">handler</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br></pre></td></tr></table></figure>

<h3 id="2-2-使用实例1"><a href="#2-2-使用实例1" class="headerlink" title="2.2 使用实例1"></a><font size=3>2.2 使用实例1</font></h3><p>【说明】此例子我们将会捕捉<code>SIGINT</code>信号，捕捉完成后，会执行我们自定的函数，而不会再使进程终止。这样的话我们想要结束进程，可以重开一个终端，然后输入以下命令：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ps -ef|grep &lt;filename&gt;  # 查看PID</span><br><span class="line">kill -9 &lt;filename_PID&gt;  # 直接杀死进程</span><br></pre></td></tr></table></figure>

<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep  */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* signal */</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="title function_">void</span> <span class="params">(*<span class="type">sighandler_t</span>)</span><span class="params">(<span class="type">int</span>)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigintHandle</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">	signal(SIGINT, sigintHandle);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;Please Enter: Ctrl+c \n&quot;</span>);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigintHandle</span><span class="params">(<span class="type">int</span> sig)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;I catch the SIGINT![%d times] \n&quot;</span>, ++count);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Please Enter: Ctrl+c </span><br><span class="line">Please Enter: Ctrl+c </span><br><span class="line">^CI catch the SIGINT![1 times] </span><br><span class="line">Please Enter: Ctrl+c </span><br><span class="line">Please Enter: Ctrl+c </span><br><span class="line">^CI catch the SIGINT![2 times]</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">后边的省略 ... ...</span></span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h3 id="2-3-使用实例2"><a href="#2-3-使用实例2" class="headerlink" title="2.3 使用实例2"></a><font size=3>2.3 使用实例2</font></h3><p>上边的例子，我们要是想再恢复<code>Ctrl+C</code>的按键功能，让它按下后进程执行默认的操作，我们该怎么来写呢？还记得<code>signal</code>函数成功情况下返回什么吗？哈哈，返回值就是指向在此之前的信号处理函数，我们在自定义处理函数中将信号的处理方式还原不就好了吗。</p>
<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep  */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* signal */</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="title function_">void</span> <span class="params">(*<span class="type">sighandler_t</span>)</span><span class="params">(<span class="type">int</span>)</span>;</span><br><span class="line"><span class="type">sighandler_t</span> oldact;</span><br><span class="line"><span class="type">void</span> <span class="title function_">sigintHandle</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">	oldact = signal(SIGINT, sigintHandle);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;Please Enter: Ctrl+c \n&quot;</span>);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigintHandle</span><span class="params">(<span class="type">int</span> sig)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;I catch the SIGINT![%d times] \n&quot;</span>, ++count);</span><br><span class="line">	signal(SIGINT, oldact);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Please Enter: Ctrl+c </span><br><span class="line">Please Enter: Ctrl+c </span><br><span class="line">Please Enter: Ctrl+c </span><br><span class="line">^CI catch the SIGINT![1 times] </span><br><span class="line">Please Enter: Ctrl+c </span><br><span class="line">Please Enter: Ctrl+c </span><br><span class="line">^C</span><br></pre></td></tr></table></figure><p>我们按下第一次的时候，成功捕捉到信号，当我们按下第二次的时候，进程退出了。</p>
              </div>
            </details>

<h2 id="3-sigaction-函数"><a href="#3-sigaction-函数" class="headerlink" title="3. sigaction() 函数"></a><font size=3>3. sigaction() 函数</font></h2><h3 id="3-1-函数说明"><a href="#3-1-函数说明" class="headerlink" title="3.1 函数说明"></a><font size=3>3.1 函数说明</font></h3><p>在<code>linux</code>下可以使用<code>man sigaction</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">sigaction</span><span class="params">(<span class="type">int</span> signum, <span class="type">const</span> <span class="keyword">struct</span> sigaction *act, <span class="keyword">struct</span> sigaction *oldact)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数用于检查或修改与指定信号相关联的处理动作（可同时进行两种操作）。系统建议使用<code>sigaction</code>函数，因为<code>signal</code>在不同类<code>UNIX</code>系统的行为不完全一样。<code>sigaction()</code>也更具灵活性以及移植性，并且它允许单独获取信号的处理函数而不是设置，并且还可以设置各种属性对调用信号处理函数时的行为施以更加精准的控制。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><p><code>signum</code>：<code>int</code>类型，表示需要设置的信号，可以是除了<code>SIGKILL</code>信号和<code>SIGSTOP</code>信号之外的任何信号。</p>
</li>
<li><p><code>act</code>：<code>struct sigaction</code>类型的结构体指针变量，指向一个<code>struct sigaction</code>数据结构，该数据结构描述了信号的处理方式。如果参数<code>act</code>不为<code>NULL</code>，则表示需要为信号设置新的处理方式；如果参数<code>act</code>为<code>NULL</code>，则表示无需改变信号当前的处理方式。</p>
</li>
<li><p><code>oldact</code>：<code>struct sigaction</code>类型的结构体指针变量，指向一个<code>struct sigaction</code>数据结构。如果参数<code>oldact</code>不为<code>NULL</code>，则会将信号之前的处理方式等信息通过参数<code>oldact</code>返回出来；如果我们不需要获取此类信息，那么可将该参数设置为<code>NULL</code>。</p>
</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 struct sigaction 结构体详情 </summary>
              <div class='content'>
              <p>使用<code>man sigaction</code>的时候，显示的帮助手册中会有这个结构体成员详情。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sigaction</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="type">void</span>     (*sa_handler)(<span class="type">int</span>);</span><br><span class="line">	<span class="type">void</span>     (*sa_sigaction)(<span class="type">int</span>, <span class="type">siginfo_t</span> *, <span class="type">void</span> *);</span><br><span class="line">	<span class="type">sigset_t</span> sa_mask;</span><br><span class="line">	<span class="type">int</span>      sa_flags;</span><br><span class="line">	<span class="type">void</span>     (*sa_restorer)(<span class="type">void</span>);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><ul><li><p><code>sa_handler</code>：指定信号处理函数，与<code>signal()</code>函数的<code>handler</code>参数相同。</p></li><li><p><code>sa_sigaction</code>：也用于指定信号处理函数，这是一个替代的信号处理函数，这个函数指针提供了更多的参数，可以通过该函数获取到更多信息，这些信号通过<code>siginfo_t</code>参数获取；<code>sa_handler</code>和<code>sa_sigaction</code>是互斥的，<strong>不能同时设置</strong>，对于标准信号来说，使用<code>sa_handler</code>就可以了，可通过<code>SA_SIGINFO</code>标志进行选择。</p></li><li><p><code>sa_mask</code>：<code>sigset_t</code>类型，该参数<code>sa_mask</code>定义了一组信号。</p></li></ul><p>当进程在执行由<code>sa_handler</code>所定义的信号处理函数之前，会先将这组信号添加到进程的信号掩码字段中，当进程执行完处理函数之后再恢复信号掩码，将这组信号从信号掩码字段中删除。当进程在执行信号处理函数期间，可能又收到了同样的信号或其它信号，从而打断当前信号处理函数的执行，这就好点像中断嵌套。</p><p>通常我们在执行信号处理函数期间不希望被另一个信号所打断，那么怎么做呢？这时候就可以通过信号掩码来实现，如果进程接收到了信号掩码中的这些信号，那么这个信号将会被阻塞暂时不能得到处理，直到这些信号从进程的信号掩码中移除。在信号处理函数调用时，进程会自动将当前处理的信号添加到信号掩码字段中，这样保证了在处理一个给定的信号时，如果此信号再次发生，那么它将会被阻塞。如果用户还需要在阻塞其它的信号，则可以通过设置参数<code>sa_mask</code>来完成，信号掩码可以避免一些信号之间的竞争状态（也称为竞态）。</p><ul><li><code>sa_flags</code>：该参数指定了一组标志，这些标志用于控制信号的处理过程，可设置为如下这些标志（多个标志使用位或<code>|</code>组合）。</li></ul><details class="folding-tag" blue><summary> 点击查看 sa_flags 常用可取的值 </summary>              <div class='content'>              <table>    <tr><td align="center" width=150px>SA_NOCLDSTOP</td><td align="left">如果signum为SIGCHLD，则子进程停止时（即当它们接收到SIGSTOP、SIGTSTP、SIGTTIN或SIGTTOU中的一种时）或恢复（即它们接收到SIGCONT）时不会收到SIGCHLD信号。</td></tr>    <tr><td align="center" width=150px>SA_NOCLDWAIT</td><td align="left">如果signum是SIGCHLD，则在子进程终止时也不会转变为僵尸进程。</td></tr>    <tr><td align="center" width=150px>SA_NODEFER  </td><td align="left">不要阻塞从某个信号自身的信号处理函数中接收此信号。也就是说当进程此时正在执行某个信号的处理函数，默认情况下，进程会自动将该信号添加到进程的信号掩码字段中，从而在执行信号处理函数期间阻塞该信号，默认情况下，我们期望进程在处理一个信号时阻塞同种信号，否则引起一些竞态条件；如果设置了SA_NODEFER标志，则表示不对它进行阻塞。</td></tr>    <tr><td align="center" width=150px>SA_RESETHAND</td><td align="left">执行完信号处理函数之后，将信号的处理方式设置为系统默认操作。</td></tr>    <tr><td align="center" width=150px>SA_RESTART  </td><td align="left">被信号中断的系统调用，在信号处理完成之后将自动重新发起。</td></tr>    <tr><td align="center" width=150px>SA_SIGINFO  </td><td align="left">如果设置了该标志，则表示使用sa_sigaction作为信号处理函数、而不是sa_handler。</td></tr></table>              </div>            </details><ul><li><code>sa_restorer</code>：该成员已过时，一般是已经不再使用了。</li></ul>
              </div>
            </details>

<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败将返回<code>-1</code>，并设置<code>errno</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigactionHandle</span><span class="params">(<span class="type">int</span> sig)</span>;<span class="comment">/* 信号处理函数声明 */</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">sigaction</span> <span class="title">act</span>;</span><span class="comment">/* 局部变量 */</span></span><br><span class="line"><span class="comment">/* 结构体变量初始化 */</span></span><br><span class="line">act.sa_handler = sigactionHandle;  <span class="comment">/* 指定信号处理函数 */</span></span><br><span class="line">act.sa_flags = <span class="number">0</span>;                  <span class="comment">/* a_flags指定了一组标志，这些标志用于控制信号的处理过程 */</span></span><br><span class="line">sigaction(SIGINT, &amp;act, <span class="literal">NULL</span>);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong>关于信号处理函数的两种形式：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 使用 sig.sa_sigaction 时*/</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">handler</span><span class="params">(<span class="type">int</span> sig, <span class="type">siginfo_t</span> *info, <span class="type">void</span> *ucontext)</span>;</span><br><span class="line"><span class="comment">/* 使用 act.sa_handler 时*/</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">handler</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br></pre></td></tr></table></figure>



<h3 id="3-2-获取信号携带的信息"><a href="#3-2-获取信号携带的信息" class="headerlink" title="3.2 获取信号携带的信息"></a><font size=3>3.2 获取信号携带的信息</font></h3><p><code>sigaction()</code>函数在<code>act</code>参数也就是第二个参数的成员<code>sa_flags</code>取<code>SA_SIGINFO</code>的时候，可以获取信号所携带的数据（如何携带数据？后边的使用实时信号一节会有介绍），此时的自定义信号处理函数形式可以如下所示：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* act.sa_flags = SA_SIGINFO */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">handler</span><span class="params">(<span class="type">int</span> sig, <span class="type">siginfo_t</span> *info, <span class="type">void</span> *ucontext)</span></span><br><span class="line">&#123;</span><br><span class="line">	...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li><code>sig</code>：<code>int</code>类型，表示接收到的信号编号。</li>
<li><code>info</code>：<code>siginfo_t</code>类型的指针变量，<code>siginfo_t</code>是一个包含信号进一步信息的结构，该信息的结构体成员中有一个成员是<code>si_value</code>，该成员类型为<code>union sigval</code>，我们获取信号携带的数据时使用的就是这个成员。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 siginfo_t 结构体成员 </summary>
              <div class='content'>
              <p>使用<code>man sigaction</code>的时候，显示的帮助手册中会有这个结构体成员详情。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">siginfo_t</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span>      si_signo;     <span class="comment">/* Signal number */</span></span><br><span class="line">	<span class="type">int</span>      si_errno;     <span class="comment">/* An errno value */</span></span><br><span class="line">	<span class="type">int</span>      si_code;      <span class="comment">/* Signal code */</span></span><br><span class="line">	<span class="type">int</span>      si_trapno;    <span class="comment">/* Trap number that caused hardware-generated signal (unused on most architectures) */</span></span><br><span class="line">	<span class="type">pid_t</span>    si_pid;       <span class="comment">/* Sending process ID */</span></span><br><span class="line">	<span class="type">uid_t</span>    si_uid;       <span class="comment">/* Real user ID of sending process */</span></span><br><span class="line">	<span class="type">int</span>      si_status;    <span class="comment">/* Exit value or signal */</span></span><br><span class="line">	<span class="type">clock_t</span>  si_utime;     <span class="comment">/* User time consumed */</span></span><br><span class="line">	<span class="type">clock_t</span>  si_stime;     <span class="comment">/* System time consumed */</span></span><br><span class="line">	<span class="class"><span class="keyword">union</span> <span class="title">sigval</span> <span class="title">si_value</span>;</span> <span class="comment">/* Signal value */</span></span><br><span class="line">	<span class="type">int</span>      si_int;       <span class="comment">/* POSIX.1b signal */</span></span><br><span class="line">	<span class="type">void</span>    *si_ptr;       <span class="comment">/* POSIX.1b signal */</span></span><br><span class="line">	<span class="type">int</span>      si_overrun;   <span class="comment">/* Timer overrun count; POSIX.1b timers */</span></span><br><span class="line">	<span class="type">int</span>      si_timerid;   <span class="comment">/* Timer ID; POSIX.1b timers */</span></span><br><span class="line">	<span class="type">void</span>    *si_addr;      <span class="comment">/* Memory location which caused fault */</span></span><br><span class="line">	<span class="type">long</span>     si_band;      <span class="comment">/* Band event (was int in glibc 2.3.2 and earlier) */</span></span><br><span class="line">	<span class="type">int</span>      si_fd;        <span class="comment">/* File descriptor */</span></span><br><span class="line">	<span class="type">short</span>    si_addr_lsb;  <span class="comment">/* Least significant bit of address (since Linux 2.6.32) */</span></span><br><span class="line">	<span class="type">void</span>    *si_lower;     <span class="comment">/* Lower bound when address violation occurred (since Linux 3.19) */</span></span><br><span class="line">	<span class="type">void</span>    *si_upper;     <span class="comment">/* Upper bound when address violation occurred (since Linux 3.19) */</span></span><br><span class="line">	<span class="type">int</span>      si_pkey;      <span class="comment">/* Protection key on PTE that caused fault (since Linux 4.6) */</span></span><br><span class="line">	<span class="type">void</span>    *si_call_addr; <span class="comment">/* Address of system call instruction (since Linux 3.5) */</span></span><br><span class="line">	<span class="type">int</span>      si_syscall;   <span class="comment">/* Number of attempted system call (since Linux 3.5) */</span></span><br><span class="line">	<span class="type">unsigned</span> <span class="type">int</span> si_arch;  <span class="comment">/* Architecture of attempted system call (since Linux 3.5) */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<ul>
<li><code>ucontext</code>：<code>void *</code>类型，该参数指向的结构包含内核保存在用户空间堆栈上的信号上下文信息， 通常，处理程序函数不使用第三个参数。 有关详细信息，请参阅 <code>sigreturn(2)</code>。 有关 <code>ucontext_t</code> 结构的更多信息可以在 <code>getcontext(3)</code> 和 <code>signal(7)</code> 中找到。</li>
</ul>
<p><strong>【注意事项】</strong>有关实例可以参考第七节的使用实时信号例子。</p>
<h3 id="3-3-使用实例1"><a href="#3-3-使用实例1" class="headerlink" title="3.3 使用实例1"></a><font size=3>3.3 使用实例1</font></h3><p>【说明】此例子我们将会捕捉<code>SIGINT</code>信号，捕捉完成后，会执行我们自定的函数，而不会再使进程终止。这样的话我们想要结束进程，可以重开一个终端，然后输入以下命令：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ps -ef|grep &lt;filename&gt;  # 查看PID</span><br><span class="line">kill -9 &lt;filename_PID&gt;  # 直接杀死进程</span><br></pre></td></tr></table></figure>

<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep  */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* sigaction sigemptyset*/</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigactionHandle</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="comment">/* 定义一个处理信号行为的结构体变量 */</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">sigaction</span> <span class="title">act</span>;</span></span><br><span class="line">	<span class="comment">/* 结构体变量初始化 */</span></span><br><span class="line">	act.sa_handler = sigactionHandle;  <span class="comment">/* 指定信号处理函数 */</span></span><br><span class="line">	act.sa_flags = <span class="number">0</span>;                  <span class="comment">/* a_flags指定了一组标志，这些标志用于控制信号的处理过程 */</span></span><br><span class="line">	sigaction(SIGINT, &amp;act, <span class="literal">NULL</span>);     <span class="comment">/* 捕捉信号 */</span></span><br><span class="line"></span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;Please Enter: Ctrl+c \n&quot;</span>);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigactionHandle</span><span class="params">(<span class="type">int</span> sig)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;I cath the SIGINT![%d times] \n&quot;</span>, ++count);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">Please Enter: Ctrl+c </span><br><span class="line">Please Enter: Ctrl+c </span><br><span class="line">^CI cath the SIGINT![1 times] </span><br><span class="line">Please Enter: Ctrl+c </span><br><span class="line">Please Enter: Ctrl+c </span><br><span class="line">^CI cath the SIGINT![2 times]</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">后边的省略 ... ...</span></span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h3 id="3-4-使用实例2"><a href="#3-4-使用实例2" class="headerlink" title="3.4 使用实例2"></a><font size=3>3.4 使用实例2</font></h3><p>上边的例子，我们要是想再恢复<code>Ctrl+C</code>的按键功能，让它按下后进程执行默认的操作，我们该怎么来写呢？这个函数与<code>signal</code>不同，我们可以直接通过参数设定执行完一次信号处理函数后恢复原来的默认操作，这个参数就是<code>act</code>参数的<code>sa_flags</code>成员。</p>
<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep  */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* sigaction sigemptyset*/</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigactionHandle</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="comment">/* 定义一个处理信号行为的结构体变量 */</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">sigaction</span> <span class="title">act</span>;</span></span><br><span class="line">	<span class="comment">/* 结构体变量初始化 */</span></span><br><span class="line">	act.sa_handler = sigactionHandle;  <span class="comment">/* 指定信号处理函数 */</span></span><br><span class="line">	act.sa_flags = SA_RESETHAND;       <span class="comment">/* a_flags指定了一组标志，这些标志用于控制信号的处理过程 */</span></span><br><span class="line">	sigaction(SIGINT, &amp;act, <span class="literal">NULL</span>);     <span class="comment">/* 捕捉信号 */</span></span><br><span class="line"></span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;Please Enter: Ctrl+c \n&quot;</span>);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigactionHandle</span><span class="params">(<span class="type">int</span> sig)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;I cath the SIGINT![%d times] \n&quot;</span>, ++count);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Please Enter: Ctrl+c </span><br><span class="line">Please Enter: Ctrl+c </span><br><span class="line">^CI cath the SIGINT![1 times] </span><br><span class="line">Please Enter: Ctrl+c </span><br><span class="line">Please Enter: Ctrl+c </span><br><span class="line">^C</span><br></pre></td></tr></table></figure><p>我们按下第一次的时候，成功捕捉到信号，当我们按下第二次的时候，进程退出了。说明信号恢复了系统的默认操作。</p>
              </div>
            </details>

<h2 id="4-子进程回收"><a href="#4-子进程回收" class="headerlink" title="4. 子进程回收"></a><font size=3>4. 子进程回收</font></h2><p>前边我们知道，子进程在结束的时候会向父进程发送一个<code>SIGCHLD</code>信号，并且父进程若是未对已结束的子进程进行回收的话，子进程就会变成僵尸进程，上边我们学习了两个信号函数，那是不是可以通过信号来实现进程的回收呢？当然也是可以的啦。<code>SIGCHLD</code>的产生会在下边三种情况下产生：</p>
<p>（1）子进程终止时。</p>
<p>（2）子进程接收到<code>SIGSTOP</code>信号停止时。</p>
<p>（3）子进程处在停止态，接受到<code>SIGCONT</code>后唤醒时。</p>
<h3 id="4-1-signal-实现进程回收"><a href="#4-1-signal-实现进程回收" class="headerlink" title="4.1 signal() 实现进程回收"></a><font size=3>4.1 signal() 实现进程回收</font></h3><p>我们可以通过<code>signal</code>函数来捕获<code>SIGCHLD</code>信号，在信号处理函数中进行进程的回收。</p>
<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span> <span class="comment">/* exit */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep fork */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* sigaction sigemptyset*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/wait.h&gt;</span> <span class="comment">/* waitpid */</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigChildHandle</span><span class="params">(<span class="type">int</span> signo)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="type">pid_t</span> pid = <span class="number">-1</span>;</span><br><span class="line">	signal(SIGCHLD, sigChildHandle);</span><br><span class="line">	pid = fork();<span class="comment">/* 创建子进程 */</span></span><br><span class="line">	<span class="keyword">if</span>(pid &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;fork error&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">else</span> <span class="keyword">if</span>(pid &gt; <span class="number">0</span>)<span class="comment">/* 父进程 */</span></span><br><span class="line">	&#123;</span><br><span class="line">		<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;The father process is runing!\n&quot;</span>);</span><br><span class="line">			sleep(<span class="number">1</span>);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">else</span> <span class="comment">/* 子进程 */</span></span><br><span class="line">	&#123;</span><br><span class="line">		<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;This is child process![i = %d]\n&quot;</span>, i);</span><br><span class="line">			sleep(<span class="number">1</span>);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;The child process is ready to exit!\n&quot;</span>);</span><br><span class="line">		<span class="built_in">exit</span>(<span class="number">0</span>);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigChildHandle</span><span class="params">(<span class="type">int</span> signo)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="keyword">if</span>(signo == SIGCHLD)</span><br><span class="line">	&#123;</span><br><span class="line">		waitpid(<span class="number">-1</span>, <span class="literal">NULL</span>,  WNOHANG);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">The father process is runing!</span><br><span class="line">This is child process![i = 0]</span><br><span class="line">The father process is runing!</span><br><span class="line">This is child process![i = 1]</span><br><span class="line">The father process is runing!</span><br><span class="line">This is child process![i = 2]</span><br><span class="line">The father process is runing!</span><br><span class="line">This is child process![i = 3]</span><br><span class="line">The father process is runing!</span><br><span class="line">This is child process![i = 4]</span><br><span class="line">The father process is runing!</span><br><span class="line">The child process is ready to exit!</span><br><span class="line">The father process is runing!</span><br><span class="line">The father process is runing!</span><br></pre></td></tr></table></figure><p>运行后，我们可以使用下边的命令查看进程以及子进程的情况：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps -ef | grep a.out </span><br></pre></td></tr></table></figure><p>会发现，使用信号捕获子进程发出的信号后，完成了对子进程的回收，回收成功是这样的：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">0 S hk         24361   19822  0  80   0 -   628 hrtime 05:48 pts/0    00:00:00 ./a.out</span><br><span class="line">0 S hk         24364   22941  0  80   0 -  4446 pipe_r 05:49 pts/2    00:00:00 grep --color=auto a.out</span><br></pre></td></tr></table></figure><p>若未回收，则子进程结束后成为僵尸进程，将会是如下状态：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">0 S hk         24350   19822  0  80   0 -   628 hrtime 05:48 pts/0    00:00:00 ./a.out</span><br><span class="line">1 Z hk         24351   24350  0  80   0 -     0 -      05:48 pts/0    00:00:00 [a.out] &lt;defunct&gt;</span><br><span class="line">0 S hk         24355   22941  0  80   0 -  4446 pipe_r 05:48 pts/2    00:00:00 grep --color=auto a.out</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h3 id="4-2-sigaction-实现进程回收"><a href="#4-2-sigaction-实现进程回收" class="headerlink" title="4.2 sigaction() 实现进程回收"></a><font size=3>4.2 sigaction() 实现进程回收</font></h3><p>我们还可以通过<code>sigaction</code>函数来捕获<code>SIGCHLD</code>信号，但是<code>sigaction</code>功能很强大，我们就可以直接在参数中设置子进程结束后不成为僵尸进程。</p>
<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span> <span class="comment">/* exit */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep fork */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* sigaction sigemptyset*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/wait.h&gt;</span> <span class="comment">/* waitpid */</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigChildHandle</span><span class="params">(<span class="type">int</span> signo)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="type">pid_t</span> pid = <span class="number">-1</span>;</span><br><span class="line">	signal(SIGCHLD, sigChildHandle);</span><br><span class="line">	pid = fork();<span class="comment">/* 创建子进程 */</span></span><br><span class="line">	<span class="keyword">if</span>(pid &lt; <span class="number">0</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		perror(<span class="string">&quot;fork error&quot;</span>);</span><br><span class="line">		<span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">else</span> <span class="keyword">if</span>(pid &gt; <span class="number">0</span>)<span class="comment">/* 父进程 */</span></span><br><span class="line">	&#123;</span><br><span class="line">		<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;The father process is runing!\n&quot;</span>);</span><br><span class="line">			sleep(<span class="number">1</span>);</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">else</span> <span class="comment">/* 子进程 */</span></span><br><span class="line">	&#123;</span><br><span class="line">		<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)</span><br><span class="line">		&#123;</span><br><span class="line">			<span class="built_in">printf</span>(<span class="string">&quot;This is child process![i = %d]\n&quot;</span>, i);</span><br><span class="line">			sleep(<span class="number">1</span>);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;The child process is ready to exit!\n&quot;</span>);</span><br><span class="line">		<span class="built_in">exit</span>(<span class="number">0</span>);</span><br><span class="line">	&#125;</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigChildHandle</span><span class="params">(<span class="type">int</span> signo)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="keyword">if</span>(signo == SIGCHLD)</span><br><span class="line">	&#123;</span><br><span class="line">		waitpid(<span class="number">-1</span>, <span class="literal">NULL</span>,  WNOHANG);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">The father process is runing!</span><br><span class="line">This is child process![i = 0]</span><br><span class="line">The father process is runing!</span><br><span class="line">This is child process![i = 1]</span><br><span class="line">The father process is runing!</span><br><span class="line">This is child process![i = 2]</span><br><span class="line">The father process is runing!</span><br><span class="line">This is child process![i = 3]</span><br><span class="line">The father process is runing!</span><br><span class="line">This is child process![i = 4]</span><br><span class="line">The father process is runing!</span><br><span class="line">The child process is ready to exit!</span><br><span class="line">I catch the signal!</span><br><span class="line">The father process is runing!</span><br></pre></td></tr></table></figure><p>运行后，我们可以使用下边的命令查看进程以及子进程的情况：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps -ef|grep a.out </span><br></pre></td></tr></table></figure><p>会发现，使用信号捕获子进程发出的信号后，完成了对子进程的回收，回收成功是这样的：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">0 S hk         24491   19822  0  80   0 -   628 hrtime 05:59 pts/0    00:00:00 ./a.out</span><br><span class="line">0 S hk         24496   22941  0  80   0 -  4446 pipe_r 05:59 pts/2    00:00:00 grep --color=auto a.out</span><br></pre></td></tr></table></figure><p>若未回收，则子进程结束后成为僵尸进程，将会是如下状态：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">0 S hk         24507   19822  0  80   0 -   628 hrtime 05:59 pts/0    00:00:00 ./a.out</span><br><span class="line">1 Z hk         24508   24507  0  80   0 -     0 -      05:59 pts/0    00:00:00 [a.out] &lt;defunct&gt;</span><br><span class="line">0 S hk         24514   22941  0  80   0 -  4446 pipe_r 06:00 pts/2    00:00:00 grep --color=auto a.out</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h2 id="5-SIGABRT-信号"><a href="#5-SIGABRT-信号" class="headerlink" title="5. SIGABRT 信号"></a><font size=3>5. SIGABRT 信号</font></h2><p><code>SIGABRT</code>信号通常是由<code>abort()</code>函数产生的，该信号来终止调用该函数的进程，<code>SIGABRT</code>信号的系统默认操作是终止进程运行、并生成核心转储文件；当调用<code>abort()</code>函数之后，内核会向进程发送<code>SIGABRT</code>信号。那这个信号能被捕获嘛？我们来试一下。</p>
<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep getpid */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* sigaction */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span> <span class="comment">/* abort */</span></span></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigactionHandle</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">sigaction</span> <span class="title">act</span>;</span>   <span class="comment">/* 定义一个处理信号行为的结构体变量 */</span></span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 1.捕获信号 */</span></span><br><span class="line">	<span class="comment">/* 1.1初始化处理信号行为的结构体变量 */</span></span><br><span class="line">	act.sa_handler = sigactionHandle;  <span class="comment">/* 指定信号处理函数 */</span></span><br><span class="line">	act.sa_flags = <span class="number">0</span>         ;           <span class="comment">/* sa_flags指定了一组标志，这些标志用于控制信号的处理过程 */</span></span><br><span class="line">	sigemptyset(&amp;act.sa_mask);           <span class="comment">/* 将信号集初始化为空 */</span></span><br><span class="line">	<span class="comment">/* 1.2设置捕捉信号 */</span></span><br><span class="line">	sigaction(SIGABRT, &amp;act, <span class="literal">NULL</span>);      <span class="comment">/* abort() 发送该信号 */</span></span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;Please send signal.[i=%d]\n&quot;</span>, ++i);</span><br><span class="line">		<span class="keyword">if</span>( i == <span class="number">3</span>)</span><br><span class="line">			<span class="built_in">abort</span>();</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigactionHandle</span><span class="params">(<span class="type">int</span> sig)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;I catch the signal [%d] %d times\n&quot;</span>, sig, ++count);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Please send signal.[i=1]</span><br><span class="line">Please send signal.[i=2]</span><br><span class="line">Please send signal.[i=3]</span><br><span class="line">I catch the signal [6] 1 times</span><br><span class="line">已放弃 (核心已转储)</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<p>事实证明，即便<code>SIGABRT</code>信号可以被捕获，但是，它依然会使程序结束。</p>
<h1 id="三、向进程发送信号"><a href="#三、向进程发送信号" class="headerlink" title="三、向进程发送信号"></a><font size=3>三、向进程发送信号</font></h1><p><code>Linux</code>系统提供了<code>kill()</code>系统调用，一个进程可通过<code>kill()</code>向另一个进程发送信号；<code>Linux</code>系统还提供了库函数<code>raise()</code>，也可用于实现发送信号的功能。</p>
<h2 id="1-kill"><a href="#1-kill" class="headerlink" title="1. kill() "></a><font size=3>1. kill() </font></h2><h3 id="1-1-函数说明"><a href="#1-1-函数说明" class="headerlink" title="1.1 函数说明"></a><font size=3>1.1 函数说明</font></h3><p>在<code>linux</code>下可以使用<code>man 2 kill </code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">kill</span><span class="params">(<span class="type">pid_t</span> pid, <span class="type">int</span> sig)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数是一个系统调用，可将信号发送给指定的进程或进程组中的每一个进程。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>pid</code>：<code>pid_t</code>类型，表示要发送信号给指定进程的<code>PID</code>号。参数<code>pid</code>为正数的情况下，用于指定接收此信号的进程<code>pid</code>；除此之外，参数<code>pid</code>也可设置为<code>0</code>或<code>-1</code>以及小于<code>-1</code>等值。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 pid 不同取值的含义 </summary>
              <div class='content'>
              <table>    <tr><td align="center" width=150px>pid &gt; 0 </td><td align="left">则信号sig将发送到pid指定的进程。</td></tr>    <tr><td align="center" width=150px>pid = 0</td><td align="left">则将sig发送到当前进程的进程组中的每个进程。</td></tr>    <tr><td align="center" width=150px>pid = -1</td><td align="left">则将sig发送到当前进程有权发送信号的每个进程，但进程1(init)除外。</td></tr>    <tr><td align="center" width=150px>pid &lt; -1</td><td align="left">则将sig发送到ID为-pid的进程组中的每个进程。</td></tr></table>
              </div>
            </details>

<ul>
<li><code>sig</code>：<code>int</code>类型，表示要发送的信号。也可设置为<code>0</code>，如果参数<code>sig</code>设置为<code>0</code>则表示不发送信号，但任执行错误检查，这通常可用于检查参数<code>pid</code>指定的进程是否存在。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败返回<code>-1</code>，并会设置<code>errno</code>。如果向一个不存在的进程发送信号，<code>kill()</code>将会返回<code>-1</code>，<code>errno</code>将被设置为<code>ESRCH</code>，表示进程不存在。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">kill(pid, sig);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong>进程中将信号发送给另一个进程是需要权限的，并不是可以随便给任何一个进程发送信号，超级用户<code>root</code>进程可以将信号发送给任何进程，但对于非超级用户（普通用户）进程来说，其基本规则是发送者进程的实际用户<code>ID</code>或有效用户<code>ID</code>必须等于接收者进程的实际用户<code>ID</code>或有效用户<code>ID</code>。</p>
<h3 id="1-2-使用实例"><a href="#1-2-使用实例" class="headerlink" title="1.2 使用实例"></a><font size=3>1.2 使用实例</font></h3><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* kill raise*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span> <span class="comment">/* getpid */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep getpid */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">pid_t</span> pid;</span><br><span class="line">	<span class="type">int</span> sig;</span><br><span class="line"></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;Please enter pid(this process pid is %d) and signal: &quot;</span>, getpid());</span><br><span class="line">	<span class="built_in">scanf</span>(<span class="string">&quot;%d %d&quot;</span>, &amp;pid, &amp;sig);</span><br><span class="line">	kill(pid, sig);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会打印提示信息，然后我们输入目标进程的<code>PID</code>和要发送的信号即可：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Please enter pid(this process pid is 24683) and signal: 24683 11</span><br><span class="line">段错误 (核心已转储)</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h2 id="2-raise"><a href="#2-raise" class="headerlink" title="2. raise() "></a><font size=3>2. raise() </font></h2><h3 id="2-1-函数说明-1"><a href="#2-1-函数说明-1" class="headerlink" title="2.1 函数说明"></a><font size=3>2.1 函数说明</font></h3><p>在<code>linux</code>下可以使用<code>man 3 raise</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">raise</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数可用于发送信号给自身，其实就等价于<code>kill(getpid(), int sig);</code>。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>sig</code>：<code>int</code>类型，表示要发送给自身的信号。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回非<code>0</code>值，失败返回<code>0</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">raise(sig);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h3 id="2-2-使用实例"><a href="#2-2-使用实例" class="headerlink" title="2.2 使用实例"></a><font size=3>2.2 使用实例</font></h3><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* kill raise*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span> <span class="comment">/* getpid */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep getpid */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> sig;</span><br><span class="line"></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;Please enter signal: &quot;</span>);</span><br><span class="line">	<span class="built_in">scanf</span>(<span class="string">&quot;%d&quot;</span>, &amp;sig);</span><br><span class="line">	raise(sig);</span><br><span class="line"></span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会打印提示信息，然后我们输入要发送的信号即可：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Please enter signal: 7</span><br><span class="line">总线错误 (核心已转储)</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h1 id="四、定时器产生信号"><a href="#四、定时器产生信号" class="headerlink" title="四、定时器产生信号"></a><font size=3>四、定时器产生信号</font></h1><h2 id="1-alarm-函数"><a href="#1-alarm-函数" class="headerlink" title="1. alarm() 函数"></a><font size=3>1. alarm() 函数</font></h2><h3 id="1-1-函数说明-1"><a href="#1-1-函数说明-1" class="headerlink" title="1.1 函数说明"></a><font size=3>1.1 函数说明</font></h3><p>在<code>linux</code>下可以使用<code>man 3 alarm</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">alarm</span><span class="params">(<span class="type">unsigned</span> <span class="type">int</span> seconds)</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数用于设置一个定时器, 在定时器超时的时候, 内核会向进程发送<code>SIGALRM</code>信号，此函数也称为<strong>闹钟函数</strong>，一个进程只能有一个闹钟时间。如果不忽略或捕捉此信号, 它的默认操作是终止调用该函数的进程。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>seconds</code>：<code>unsigned int</code>类型，设置定时时间，以秒为单位；如果参数<code>seconds</code>等于<code>0</code>，则表示取消之前设置的<code>alarm</code>闹钟。</li>
</ul>
<p><strong>【返回值】</strong><code>unsigned int</code>类型，如果在调用<code>alarm()</code>之前已经为该进程设置了<code>alarm</code>闹钟，但是还没有超时，则已经设置的闹钟的剩余值作为本次<code>alarm()</code>函数调用的返回值，之前设置的闹钟则被新的替代；否则返回<code>0</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">alarm(seconds);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong></p>
<p>（1）参数<code>seconds</code>的值是产生<code>SIGALRM</code>信号需要经过的时钟秒数，当这一刻到达时，由内核产生该信号，每个进程只能设置一个<code>alarm</code>闹钟；虽然<code>SIGALRM</code>信号的系统默认操作是终止进程。<br>（2）<code>alarm</code>闹钟并不能循环触发，只能触发一次，若想要实现循环触发，可以在<code>SIGALRM</code>信号处理函数中再次调用<code>alarm()</code>函数设置定时器。</p>
<h3 id="1-2-使用实例1"><a href="#1-2-使用实例1" class="headerlink" title="1.2 使用实例1"></a><font size=3>1.2 使用实例1</font></h3><details class="folding-tag" blue><summary> 点击查看实例1 </summary>
              <div class='content'>
              <p>该实例为单次触发<code>alarm</code>闹钟。</p><figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* alarm sleep*/</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	alarm(<span class="number">5</span>);<span class="comment">/* 5s后向本进程发送 SIGALRM 信号，将会终止程序*/</span></span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;i = %d\n&quot;</span>, ++i);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会显示如下信息：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">i = 1</span><br><span class="line">i = 2</span><br><span class="line">i = 3</span><br><span class="line">i = 4</span><br><span class="line">i = 5</span><br><span class="line">闹钟</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h3 id="1-3-使用实例2"><a href="#1-3-使用实例2" class="headerlink" title="1.3 使用实例2"></a><font size=3>1.3 使用实例2</font></h3><details class="folding-tag" blue><summary> 点击查看实例2 </summary>
              <div class='content'>
              <p>该实例为循环触发<code>alarm</code>闹钟。</p><figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* alarm sleep*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* signal */</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigHandle</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	signal(SIGALRM, sigHandle);</span><br><span class="line">	alarm(<span class="number">5</span>);<span class="comment">/* 5s后向本进程发送 SIGALRM 信号，将会终止程序*/</span></span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;i = %d\n&quot;</span>, ++i);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigHandle</span><span class="params">(<span class="type">int</span> sig)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">1</span>;</span><br><span class="line">	<span class="keyword">if</span> (sig == SIGALRM)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;[%d] timer \n&quot;</span>, ++count);</span><br><span class="line">		alarm(<span class="number">5</span>);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会显示以下信息：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">i = 1</span><br><span class="line">i = 2</span><br><span class="line">i = 3</span><br><span class="line">i = 4</span><br><span class="line">i = 5</span><br><span class="line">[2] timer </span><br><span class="line">i = 6</span><br><span class="line">i = 7</span><br><span class="line">i = 8</span><br><span class="line">i = 9</span><br><span class="line">i = 10</span><br><span class="line">[3] timer </span><br><span class="line">i = 11</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">后边的省略 ... ...</span></span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h2 id="2-ualarm-函数"><a href="#2-ualarm-函数" class="headerlink" title="2. ualarm() 函数"></a><font size=3>2. ualarm() 函数</font></h2><h3 id="2-1-函数说明-2"><a href="#2-1-函数说明-2" class="headerlink" title="2.1 函数说明"></a><font size=3>2.1 函数说明</font></h3><p>在<code>linux</code>下可以使用<code>man 3 ualarm</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">useconds_t</span> <span class="title function_">ualarm</span><span class="params">(<span class="type">useconds_t</span> usecs, <span class="type">useconds_t</span> interval)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数用于设置一个循环发送<code>SIGALRM</code>信号的定时器，函数会在<code>usecs</code>微秒后，将<code>SIGALRM</code>信号发送给进程，并且之后每隔<code>interval</code>微秒再发送一次 <code>SIGALRM</code>信号。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>usecs</code>：<code>useconds_t</code>类型，设置定时时间，以微秒为单位，不能大于<code>1000 000us</code>。</li>
<li><code>interval</code>：<code>useconds_t</code>类型，设置循环发送信号的间隔时间，以微妙为单位，不能大于<code>1000 000us</code>。</li>
</ul>
<p><strong>【返回值】</strong><code>unsigned int</code>类型，如果在调用<code>ualarm()</code>之前已经为该进程设置了<code>ualarm</code>闹钟，但是还没有超时，则已经设置的闹钟的剩余值作为本次<code>ualarm()</code>函数调用的返回值，之前设置的闹钟则被新的替代；否则返回<code>0</code>（第一次调用该函数也返回<code>0</code>）。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">ualarm(<span class="type">useconds_t</span> usecs, <span class="type">useconds_t</span> interval);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong>在<code>ualarm</code>函数的手册中，返回值的错误信息中有这么一条：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">ERRORS</span><br><span class="line">       EINTR  Interrupted by a signal; see signal(7).</span><br><span class="line"></span><br><span class="line">       EINVAL usecs or interval is not smaller  than  1000000.   (On systems where that is considered an error.)</span><br></pre></td></tr></table></figure>

<p>这就意味着，我们的两个参数最好都不要大于<code>1s</code>，否则闹钟是不会生效的。</p>
<h3 id="2-2-使用实例-1"><a href="#2-2-使用实例-1" class="headerlink" title="2.2 使用实例"></a><font size=3>2.2 使用实例</font></h3><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* ualarm sleep*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* signal */</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigHandle</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	signal(SIGALRM, sigHandle);</span><br><span class="line">	ualarm(<span class="number">999999</span>, <span class="number">999999</span>);</span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;i = %d\n&quot;</span>, ++i);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigHandle</span><span class="params">(<span class="type">int</span> sig)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">1</span>;</span><br><span class="line">	<span class="keyword">if</span> (sig == SIGALRM)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;[%d] timer \n&quot;</span>, ++count);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会显示如下信息：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">i = 1</span><br><span class="line">[2] timer </span><br><span class="line">i = 2</span><br><span class="line">[3] timer </span><br><span class="line">i = 3</span><br><span class="line">[4] timer </span><br><span class="line">i = 4</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">后边的省略 ... ...</span></span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h2 id="3-setitimer-函数"><a href="#3-setitimer-函数" class="headerlink" title="3. setitimer() 函数"></a><font size=3>3. setitimer() 函数</font></h2><h3 id="3-1-函数说明-1"><a href="#3-1-函数说明-1" class="headerlink" title="3.1 函数说明"></a><font size=3>3.1 函数说明</font></h3><p>在<code>linux</code>下可以使用<code>man 2 setitimer</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/time.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">setitimer</span><span class="params">(<span class="type">int</span> which, <span class="type">const</span> <span class="keyword">struct</span> itimerval *new_value, <span class="keyword">struct</span> itimerval *old_value)</span>;</span><br><span class="line"> </span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数用于设置一个定时器，可以定时发送信号。可替代<code>alarm</code>函数，比<code>alarm</code>函数精确度更高，可以实现周期定时。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>which</code>：<code>int</code>类型，设置定时的方式，一共有三种定时方式，每种都工作在不同的时钟上，并且在定时器定时结束时产生不同的信号。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 which 取值 </summary>
              <div class='content'>
              <table>    <tr><td align="center" width=150px>ITIMER_REAL</td><td align="left">按实际时间计时，到达时间的时候会产生SIGALRM信号</td></tr>    <tr><td align="center" width=150px>ITIMER_VIRTUAL</td><td align="left">这种方式根据进程消耗的用户模式CPU时间进行计时。(测量包括进程中所有线程消耗的CPU时间)在每次到期时，都会生成一个SIGVTALRM信号。</td></tr>    <tr><td align="center" width=150px>ITIMER_PROF</td><td align="left">根据进程消耗的总CPU时间（即用户和系统）进行倒计时，每次到期时，发送SIGPROF信号</td></tr></table>
              </div>
            </details>

<ul>
<li><code>new_value</code>：<code>struct itimerval</code>类型的结构体指针变量，是传入参数，表示设定定时的时长，也就是超时时间。它有两个成员<code>it_interval</code>和<code>it_value</code>，分别用于设置间隔时间和定时时间，如果<code>it_value</code>为0，那么定时器将不不会启动；如果计时器<code>it_value</code>过期之后，<code>it_interval</code>为0，那么定时器也将停止工作。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 struct itimerval 结构体说明 </summary>
              <div class='content'>
              <p>使用<code>man 2 setitimer</code>的时候，显示的帮助手册中会有这个结构体成员详情。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">itimerval</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">timeval</span> <span class="title">it_interval</span>;</span> <span class="comment">/* Interval for periodic timer */</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">timeval</span> <span class="title">it_value</span>;</span>    <span class="comment">/* Time until next expiration */</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">timeval</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="type">time_t</span>      tv_sec;         <span class="comment">/* seconds */</span></span><br><span class="line">	<span class="type">suseconds_t</span> tv_usec;        <span class="comment">/* microseconds */</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><ul><li><code>it_interval</code>：<code>struct timeval</code>类型，表示定时器循环的时间间隔，即第一次计时<code>it_value</code>时长发送信号，再往后的信号每隔一个<code>it_interval</code>发送一次。它有两个成员，为<code>tv_sec</code>和<code>tv_usec</code>，用于设置时间，分别表示秒和微秒。</li><li><code>it_value</code>：<code>struct timeval</code>类型，表示定时器定时时长，算起来应该是第一次启动定时器的定时时间，它有两个成员，为<code>tv_sec</code>和<code>tv_usec</code>，分别表示秒和微秒。</li></ul>
              </div>
            </details>

<ul>
<li><code>old_value</code>：<code>struct itimerval</code>类型的结构体指针变量，是传出参数，表示上一次定时剩余的时间，如果不关心上一次定时剩余时间，可以设置为<code>NULL</code>。例如第一次定时<code>10</code>s，但是过了<code>6s</code>后，再次用<code>setitimer</code>函数定时，此时第二次的计时会将第一次计时覆盖，而上一次定时的剩余时间则为<code>4s</code>。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败将返回<code>-1</code>，并设置<code>errno</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/time.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">itimerval</span> <span class="title">timevalue</span>;</span></span><br><span class="line">timevalue.it_interval.tv_sec = <span class="number">2</span>;  <span class="comment">/* 触发周期 s */</span></span><br><span class="line">timevalue.it_interval.tv_usec = <span class="number">0</span>; <span class="comment">/* 触发周期 us */</span></span><br><span class="line">timevalue.it_value.tv_sec = <span class="number">5</span>;     <span class="comment">/* 触发时间 s */</span></span><br><span class="line">timevalue.it_value.tv_usec = <span class="number">0</span>;    <span class="comment">/* 触发时间 us */</span></span><br><span class="line">setitimer(ITIMER_REAL, &amp;timevalue, <span class="literal">NULL</span>);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h3 id="3-2-使用实例"><a href="#3-2-使用实例" class="headerlink" title="3.2 使用实例"></a><font size=3>3.2 使用实例</font></h3><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* ualarm sleep*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* signal */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/time.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigHandle</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">itimerval</span> <span class="title">timevalue</span>;</span></span><br><span class="line">	<span class="comment">/* 时间参数结构体变量初始化 */</span></span><br><span class="line">    timevalue.it_interval.tv_sec = <span class="number">2</span>;  <span class="comment">/* 触发周期 s */</span></span><br><span class="line">    timevalue.it_interval.tv_usec = <span class="number">0</span>; <span class="comment">/* 触发周期 us */</span></span><br><span class="line">	</span><br><span class="line">    timevalue.it_value.tv_sec = <span class="number">5</span>;     <span class="comment">/* 触发时间 s */</span></span><br><span class="line">    timevalue.it_value.tv_usec = <span class="number">0</span>;    <span class="comment">/* 触发时间 us */</span></span><br><span class="line">	<span class="comment">/* 设置定时器，5秒后触发信号，之后每隔2秒触发一次 */</span></span><br><span class="line">	setitimer(ITIMER_REAL, &amp;timevalue, <span class="literal">NULL</span>);</span><br><span class="line">	<span class="comment">/* 捕捉信号 */</span></span><br><span class="line">	signal(SIGALRM, sigHandle);</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;i = %d\n&quot;</span>, ++i);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigHandle</span><span class="params">(<span class="type">int</span> sig)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">1</span>;</span><br><span class="line">	<span class="keyword">if</span> (sig == SIGALRM)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;[%d] timer \n&quot;</span>, ++count);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会显示如下信息：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">i = 1</span><br><span class="line">i = 2</span><br><span class="line">i = 3</span><br><span class="line">i = 4</span><br><span class="line">i = 5</span><br><span class="line">[2] timer </span><br><span class="line">i = 6</span><br><span class="line">i = 7</span><br><span class="line">[3] timer </span><br><span class="line">i = 8</span><br><span class="line">i = 9</span><br><span class="line">[4] timer </span><br><span class="line">i = 10</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">后边的省略 ... ...</span></span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h2 id="4-getitimer-函数"><a href="#4-getitimer-函数" class="headerlink" title="4. getitimer() 函数"></a><font size=3>4. getitimer() 函数</font></h2><h3 id="4-1-getitimer"><a href="#4-1-getitimer" class="headerlink" title="4.1 getitimer() "></a><font size=3>4.1 getitimer() </font></h3><p>在<code>linux</code>下可以使用<code>man 2 getitimer</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/time.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">getitimer</span><span class="params">(<span class="type">int</span> which, <span class="keyword">struct</span> itimerval *curr_value)</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数用于将定时器的当前值填写在<code>curr_value</code>指向的结构体中，也就是获取定时器的当前值，该函数不会发送信号。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>which</code>：<code>int</code>类型，定时的方式，一共有三种定时方式，每种都工作在不同的时钟上，并且在定时器定时结束时产生不同的信号。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 which 取值 </summary>
              <div class='content'>
              <table>    <tr><td align="center" width=150px>ITIMER_REAL</td><td align="left">按实际时间计时，到达时间的时候会产生SIGALRM信号</td></tr>    <tr><td align="center" width=150px>ITIMER_VIRTUAL</td><td align="left">这种方式根据进程消耗的用户模式CPU时间进行计时。(测量包括进程中所有线程消耗的CPU时间)在每次到期时，都会生成一个SIGVTALRM信号。</td></tr>    <tr><td align="center" width=150px>ITIMER_PROF</td><td align="left">根据进程消耗的总CPU时间（即用户和系统）进行倒计时，每次到期时，发送SIGPROF信号</td></tr></table>
              </div>
            </details>

<ul>
<li><code>curr_value</code>：<code>struct itimerval</code>类型的结构体指针变量，用于保存当前定时器的值。它有两个成员<code>it_interval</code>和<code>it_value</code>，分别用于存放已开启的定时器的间隔时间和定时时间。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败将返回<code>-1</code>，并设置<code>errno</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/time.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">itimerval</span> <span class="title">nowvalue</span>;</span></span><br><span class="line">getitimer(ITIMER_REAL, &amp;nowvalue);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h3 id="4-2-使用实例"><a href="#4-2-使用实例" class="headerlink" title="4.2 使用实例"></a><font size=3>4.2 使用实例</font></h3><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* ualarm sleep*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* signal */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/time.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigHandle</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">itimerval</span> <span class="title">timevalue</span>;</span></span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">itimerval</span> <span class="title">nowvalue</span>;</span></span><br><span class="line">	<span class="comment">/* 时间参数结构体变量初始化 */</span></span><br><span class="line">    timevalue.it_interval.tv_sec = <span class="number">2</span>;  <span class="comment">/* 触发周期 s */</span></span><br><span class="line">    timevalue.it_interval.tv_usec = <span class="number">0</span>; <span class="comment">/* 触发周期 us */</span></span><br><span class="line">	</span><br><span class="line">    timevalue.it_value.tv_sec = <span class="number">5</span>;     <span class="comment">/* 触发时间 s */</span></span><br><span class="line">    timevalue.it_value.tv_usec = <span class="number">0</span>;    <span class="comment">/* 触发时间 us */</span></span><br><span class="line">	<span class="comment">/* 设置定时器，5秒后触发信号，之后每隔2秒触发一次 */</span></span><br><span class="line">	setitimer(ITIMER_REAL, &amp;timevalue, <span class="literal">NULL</span>);</span><br><span class="line">	<span class="comment">/* 捕捉信号 */</span></span><br><span class="line">	signal(SIGALRM, sigHandle);</span><br><span class="line">	</span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		getitimer(ITIMER_REAL, &amp;nowvalue);</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;[i = %d]: it_interval=%lds %ldus;it_value=%lds %ldus.\n&quot;</span>, ++i, </span><br><span class="line">				nowvalue.it_interval.tv_sec,</span><br><span class="line">				nowvalue.it_interval.tv_usec, </span><br><span class="line">				nowvalue.it_value.tv_sec,</span><br><span class="line">				nowvalue.it_value.tv_usec);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigHandle</span><span class="params">(<span class="type">int</span> sig)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">1</span>;</span><br><span class="line">	<span class="keyword">if</span> (sig == SIGALRM)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;[%d] timer \n&quot;</span>, ++count);</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会显示如下信息：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">[i = 1]: it_interval=2s 0us;it_value=4s 999993us.</span><br><span class="line">[i = 2]: it_interval=2s 0us;it_value=3s 999406us.</span><br><span class="line">[i = 3]: it_interval=2s 0us;it_value=2s 998224us.</span><br><span class="line">[i = 4]: it_interval=2s 0us;it_value=1s 997261us.</span><br><span class="line">[i = 5]: it_interval=2s 0us;it_value=0s 996504us.</span><br><span class="line">[2] timer </span><br><span class="line">[i = 6]: it_interval=2s 0us;it_value=1s 999322us.</span><br><span class="line">[i = 7]: it_interval=2s 0us;it_value=0s 998594us.</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">后边的省略 ... ...</span></span><br></pre></td></tr></table></figure>
              </div>
            </details>

<h1 id="五、信号集与信号阻塞"><a href="#五、信号集与信号阻塞" class="headerlink" title="五、信号集与信号阻塞"></a><font size=3>五、信号集与信号阻塞</font></h1><p>在上边，当我们的信号来临的时候，马上就开始执行信号处理函数了，这个时候，我们的主进程就会被打断，但是，有的时候，主进程正在执行一些很重要的事情，不希望被打断，就像我们正在跟女朋友视频电话，但是好基友发来消息说“王者？”，啊，，，这，，，当然是女朋友更重要啦，我们可以等跟女朋友视频完毕再跟好友打游戏，好友发来的消息就像信号，我们不希望马上去执行，但是又希望这个信号不会消失，暂时忽略掉，当我们做完一些事后再去处理这个信号，这一部分就是关于这样如何实现的一些笔记啦。</p>
<h2 id="1-相关的概念"><a href="#1-相关的概念" class="headerlink" title="1. 相关的概念"></a><font size=3>1. 相关的概念</font></h2><h3 id="1-1-信号的状态"><a href="#1-1-信号的状态" class="headerlink" title="1.1 信号的状态"></a><font size=3>1.1 信号的状态</font></h3><p>信号产生后有三种状态，分别是信号递达状态、信号未决和信号阻塞状态：</p>
<ul>
<li><strong>信号递达</strong>（<code>delivery</code> ）</li>
</ul>
<p>实际信号执行的处理过程(<code>3</code>种状态：忽略，执行默认动作或者捕获)。</p>
<ul>
<li><strong>信号未决</strong>（<code>pending</code>）</li>
</ul>
<p>从产生到递达之间的状态。</p>
<ul>
<li><strong>信号阻塞</strong>（<code>block</code>）</li>
</ul>
<p>被阻塞的信号产生时将一直保持在未决状态，直到进程解除对此信号的阻塞, 才执⾏递达的动作。我们有时候不希望在接到信号时就立即停止当前执行，去处理信号，同时也不希望忽略该信号，而是延时一段时间去调用信号处理函数。这种情况就可以通过<strong>阻塞信号</strong>实现。信号的”阻塞“是一个开关动作，指的是<strong>阻止信号被处理，但不是阻止信号产生</strong>。所以信号被阻塞，实际上是当该信号产生后，进程将此信号的状态保持为未决(<code>pending</code>)状态,直到对该信号解除了阻塞或将该信号的动作改为忽略。</p>
<p><strong>【注意事项】</strong>信号阻塞和忽略的区别：</p>
<p>（1）忽略是进程对信号的一种处理方式，它属于信号递达状态。而阻塞是跟信号递达同级的概念。</p>
<p>（2）只要信号被阻塞就不会递达，而忽略是在递达之后可选的一种处理动作。</p>
<h3 id="1-2-信号的存储"><a href="#1-2-信号的存储" class="headerlink" title="1.2 信号的存储"></a><font size=3>1.2 信号的存储</font></h3><p>信号的不同状态在进程的<code>PCB</code>中对应不同的表，三种状态就有三个表对应</p>
<img data-src="https://fanhua-picture.oss-cn-hangzhou.aliyuncs.com/01%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91/01HQ%E8%AF%BE%E7%A8%8B%E4%BD%93%E7%B3%BB/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/LV05-05-%E8%BF%9B%E7%A8%8B%E9%80%9A%E4%BF%A1-03-%E4%BF%A1%E5%8F%B7/img/image-20220608163829684.png" alt="image-20220608163829684" style="zoom: 50%;" />

<p>前两张表都是位图（<code>BitSet</code>）来存储的。信号被阻塞就将相应位置<code>1</code>，否则置<code>0</code>。而<code>pending</code>表中，若置<code>1</code>则表示信号存在，<code>0</code>则相反。也就是说，<code>pending</code>表中的数据是判断信号是否存在的唯一依据。上图中的三个信号状态说明如下：</p>
<ul>
<li><code>SIGHUP</code>信号未阻塞也未产生过，但当它递达的时候就会执行默认处理动作。</li>
<li><code>SIGINT</code>信号产生过，但已被阻塞。所以暂时不能递达，虽然它的处理动作是忽略，但在没有解除阻塞之前不能忽略这个信号，这是因为进程仍有机会改变处理动作之后再解除阻塞。</li>
<li><code>SIGQUIT</code>信号未产生过，一旦产⽣将被阻塞，它的处理动作是用户自定义的捕捉函数<code>sigHandler</code>。</li>
</ul>
<p>如果在进程解除对信号的阻塞之前，该信号产生过多次，将会如何处理呢？</p>
<ul>
<li><code>POSIX.1</code>允许系统递送该信号一次或多次。</li>
<li><code>Linux</code>是这样规定的：常规信号(<code>1-31</code>)在递达之前产生多次只记一次，而实时信号(<code>34-64</code>)在递达之前产生多次，并可以依次放在一个队列中。</li>
</ul>
<h3 id="1-3-信号集"><a href="#1-3-信号集" class="headerlink" title="1.3 信号集"></a><font size=3>1.3 信号集</font></h3><p>信号未决和信号阻塞标志都可以用相同的数据结构（位图）存储，所以它们可以用同一数据类型来表示，在<code>linux</code>中这个数据类型就是<code>sigset_t</code>。这个结构体在哪里定义的呢？我们还是要通过<code>locate</code>命令来查找一些文件的位置，</p>
<p>首先是<code>signal.h</code>文件中有如下定义：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="type">__sigset_t</span> <span class="type">sigset_t</span>;</span><br></pre></td></tr></table></figure>

<p>额，按理说应该再去找<code>__sigset</code>的定义，但是回到开头一看，有这么一条语句：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;bits/sigset.h&gt;</span>                <span class="comment">/* __sigset_t, __sig_atomic_t.  */</span></span></span><br></pre></td></tr></table></figure>

<p>于是我们立刻可以定位到<code>bits/sigset.h</code>文件中，打开该文件并查找<code>__sigset_t</code>的定义如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* A `sigset_t&#x27; has a bit for each signal.  */</span></span><br><span class="line"></span><br><span class="line"><span class="meta"># <span class="keyword">define</span> _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span></span></span><br><span class="line"><span class="class">  &#123;</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">long</span> <span class="type">int</span> __val[_SIGSET_NWORDS];</span><br><span class="line">  &#125; <span class="type">__sigset_t</span>;</span><br></pre></td></tr></table></figure>

<p>而<code>sigset_t</code>就被称为<strong>信号集</strong>，这个类型可以<strong>表示每个信号的“有效”或“无效”状态</strong>。在<strong>阻塞信号集</strong>其含义是该信号是否被阻塞；在<strong>未决信号集</strong>中就代表该信号是否处于未决状态。</p>
<p>另外，阻塞信号集也可以叫做当前进程的**信号屏蔽字(Signal Mask)**，而这里的屏蔽我们应该理解为阻塞而不是忽略。</p>
<p>【注意事项】虽然信号的未决和阻塞状态都是用位图来表示的，但是不可以通过移位操作来改变信号状态，统对于信号集有特定的<strong>信号集操作函数</strong>，我们只能调用这些操作函数来改变信号状态。</p>
<h2 id="2-信号集相关操作"><a href="#2-信号集相关操作" class="headerlink" title="2. 信号集相关操作"></a><font size=3>2. 信号集相关操作</font></h2><h3 id="2-1-初始化信号集"><a href="#2-1-初始化信号集" class="headerlink" title="2.1 初始化信号集"></a><font size=3>2.1 初始化信号集</font></h3><h4 id="2-1-1-sigemptyset"><a href="#2-1-1-sigemptyset" class="headerlink" title="2.1.1 sigemptyset() "></a><font size=3>2.1.1 sigemptyset() </font></h4><h5 id="2-1-1-1-函数说明"><a href="#2-1-1-1-函数说明" class="headerlink" title="2.1.1.1 函数说明"></a><font size=3>2.1.1.1 函数说明</font></h5><p>在<code>linux</code>下可以使用<code>man 3 sigemptyset </code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">sigemptyset</span><span class="params">(<span class="type">sigset_t</span> *<span class="built_in">set</span>)</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数初始化一个信号集，使其不<strong>包含任何信号</strong>，也就是将一个信号集初始化为空。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>set</code>：<code>sigset_t</code>类型指针变量，表示需要进行初始化的信号集变量。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败将返回<code>-1</code>，并设置<code>errno</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">sigset_t</span> sigset;</span><br><span class="line">sigemptyset(&amp;sigset);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h5 id="2-1-1-2-使用实例"><a href="#2-1-1-2-使用实例" class="headerlink" title="2.1.1.2 使用实例"></a><font size=3>2.1.1.2 使用实例</font></h5><p>暂无。</p>
<h4 id="2-1-2-sigfillset"><a href="#2-1-2-sigfillset" class="headerlink" title="2.1.2 sigfillset() "></a><font size=3>2.1.2 sigfillset() </font></h4><h5 id="2-1-2-1-函数说明"><a href="#2-1-2-1-函数说明" class="headerlink" title="2.1.2.1 函数说明"></a><font size=3>2.1.2.1 函数说明</font></h5><p>在<code>linux</code>下可以使用<code>man 3 sigfillset </code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">sigfillset</span><span class="params">(<span class="type">sigset_t</span> *<span class="built_in">set</span>)</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数初始化一个信号集为满，就是将所有信号加入该信号集。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>set</code>：<code>sigset_t</code>类型指针变量，表示需要进行初始化的信号集变量。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败将返回<code>-1</code>，并设置<code>errno</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">sigset_t</span> sigset;</span><br><span class="line">sigfillset(&amp;sigset);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h5 id="2-1-2-2-使用实例"><a href="#2-1-2-2-使用实例" class="headerlink" title="2.1.2.2 使用实例"></a><font size=3>2.1.2.2 使用实例</font></h5><p>暂无。</p>
<h3 id="2-2-向信号集添加信号"><a href="#2-2-向信号集添加信号" class="headerlink" title="2.2 向信号集添加信号"></a><font size=3>2.2 向信号集添加信号</font></h3><h4 id="2-2-1-sigaddset"><a href="#2-2-1-sigaddset" class="headerlink" title="2.2.1 sigaddset() "></a><font size=3>2.2.1 sigaddset() </font></h4><h5 id="2-2-1-1-函数说明"><a href="#2-2-1-1-函数说明" class="headerlink" title="2.2.1.1 函数说明"></a><font size=3>2.2.1.1 函数说明</font></h5><p>在<code>linux</code>下可以使用<code>man 3 sigaddset</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">sigaddset</span><span class="params">(<span class="type">sigset_t</span> *<span class="built_in">set</span>, <span class="type">int</span> signum)</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数向信号集中添加一个信号。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>set</code>：<code>sigset_t</code>类型指针变量，表示已经初始化过的信号集变量。</li>
<li><code>signum</code>：<code>int</code>类型，表示要添加到信号集中的信号。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败将返回<code>-1</code>，并设置<code>errno</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">sigset_t</span> sigset;</span><br><span class="line">sigemptyset(&amp;sigset);</span><br><span class="line"></span><br><span class="line">sigaddset(sigset, signum);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h5 id="2-2-1-2-使用实例"><a href="#2-2-1-2-使用实例" class="headerlink" title="2.2.1.2 使用实例"></a><font size=3>2.2.1.2 使用实例</font></h5><p>暂无。</p>
<h3 id="2-3-从信号集删除信号"><a href="#2-3-从信号集删除信号" class="headerlink" title="2.3 从信号集删除信号"></a><font size=3>2.3 从信号集删除信号</font></h3><h4 id="2-3-1-sigdelset"><a href="#2-3-1-sigdelset" class="headerlink" title="2.3.1 sigdelset() "></a><font size=3>2.3.1 sigdelset() </font></h4><h5 id="2-3-1-1-函数说明"><a href="#2-3-1-1-函数说明" class="headerlink" title="2.3.1.1 函数说明"></a><font size=3>2.3.1.1 函数说明</font></h5><p>在<code>linux</code>下可以使用<code>man 3 sigdelset</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">sigdelset</span><span class="params">(<span class="type">sigset_t</span> *<span class="built_in">set</span>, <span class="type">int</span> signum)</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数从信号集中删除一个信号。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>set</code>：<code>sigset_t</code>类型指针变量，表示已经初始化过的信号集变量。</li>
<li><code>signum</code>：<code>int</code>类型，表示要从信号集中删除的信号。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败将返回<code>-1</code>，并设置<code>errno</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">sigset_t</span> sigset;</span><br><span class="line">sigfillset(&amp;sigset);</span><br><span class="line"></span><br><span class="line">sigdelset(sigset, signum);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h5 id="2-3-1-2-使用实例"><a href="#2-3-1-2-使用实例" class="headerlink" title="2.3.1.2 使用实例"></a><font size=3>2.3.1.2 使用实例</font></h5><p>暂无。</p>
<h3 id="2-4-测试信号是否在信号集"><a href="#2-4-测试信号是否在信号集" class="headerlink" title="2.4 测试信号是否在信号集"></a><font size=3>2.4 测试信号是否在信号集</font></h3><h4 id="2-4-1-sigismember"><a href="#2-4-1-sigismember" class="headerlink" title="2.4.1 sigismember() "></a><font size=3>2.4.1 sigismember() </font></h4><h5 id="2-4-1-1-函数说明"><a href="#2-4-1-1-函数说明" class="headerlink" title="2.4.1.1 函数说明"></a><font size=3>2.4.1.1 函数说明</font></h5><p>在<code>linux</code>下可以使用<code>man 3 sigismember</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">sigismember</span><span class="params">(<span class="type">const</span> <span class="type">sigset_t</span> *<span class="built_in">set</span>, <span class="type">int</span> signum)</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数检测一个信号是否在指定的信号集中。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>set</code>：<code>sigset_t</code>类型指针变量，表示已经初始化过的信号集变量。</li>
<li><code>signum</code>：<code>int</code>类型，表示要需要测试的信号。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，如果信号在信号集中，则返回<code>1</code>；如果不在信号集中，则返回<code>0</code>，失败则返回<code>-1</code>，并设置<code>errno</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">sigset_t</span> sigset;</span><br><span class="line">sigfillset(&amp;sigset);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (sigismember(&amp;sig_set, SIGINT) == <span class="number">1</span>)</span><br><span class="line">    ...</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h5 id="2-4-1-2-使用实例"><a href="#2-4-1-2-使用实例" class="headerlink" title="2.4.1.2 使用实例"></a><font size=3>2.4.1.2 使用实例</font></h5><p>暂无。</p>
<h2 id="3-阻塞信号"><a href="#3-阻塞信号" class="headerlink" title="3. 阻塞信号"></a><font size=3>3. 阻塞信号</font></h2><h3 id="3-1-信号掩码"><a href="#3-1-信号掩码" class="headerlink" title="3.1 信号掩码"></a><font size=3>3.1 信号掩码</font></h3><p><code>Linux</code>内核为每一个进程维护了一个<strong>信号掩码</strong>（其实就是一个信号集，严格来说就是前边提到的<strong>信号屏蔽字</strong>或者叫<strong>阻塞信号集</strong>），即一组信号。当进程接收到一个属于信号掩码中定义的信号时，该信号将会被阻塞、无法传递给进程进行处理，那么内核会将其阻塞，直到该信号从信号掩码中移除，内核才会把该信号传递给进程从而得到处理。</p>
<p>那么，如何将一个信号添加到信号掩码中去呢？大概有三种途径：</p>
<p>（1）当应用程序调用<code>signal()</code>或<code>sigaction()</code>函数为某一个信号设置处理方式时，进程会自动将该信号添加到信号掩码中，这样保证了在处理一个给定的信号时，如果此信号再次发生，那么它将会被阻塞；对于<code>sigaction()</code>而言，是否会如此，需要根据<code>sigaction()</code>函数是否设置了<code>SA_NODEFER</code>标志而定；当信号处理函数结束返回后，会自动将该信号从信号掩码中移除。</p>
<p>（2）使用<code>sigaction()</code>函数为信号设置处理方式时，可以额外指定一组信号，当调用信号处理函数时将该组信号自动添加到信号掩码中，当信号处理函数结束返回后，再将这组信号从信号掩码中移除；通过<code>sa_mask</code>参数进行设置。</p>
<p>（3）使用<code>sigprocmask()</code>系统调用，可以显式地向信号掩码中添加或者移除信号。</p>
<h3 id="3-2-sigprocmask-函数"><a href="#3-2-sigprocmask-函数" class="headerlink" title="3.2 sigprocmask() 函数"></a><font size=3>3.2 sigprocmask() 函数</font></h3><h4 id="3-2-1-函数说明"><a href="#3-2-1-函数说明" class="headerlink" title="3.2.1 函数说明"></a><font size=3>3.2.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man</code>命令查看该函数的帮助手册。大概会有两种函数声明形式，但是其实是一样的，形式二已经弃用，但是有些地方可能还是会看到，因此还是使用形式一比较好，形式二仅作了解吧。</p>
<div class="tabs" id="tabname2"><ul class="nav-tabs"><li class="tab active"><a href="#tabname2-1">声明形式一</a></li><li class="tab"><a href="#tabname2-2">声明形式二</a></li></ul><div class="tab-content"><div class="tab-pane active" id="tabname2-1"><p>【说明】使用的命令为<code>man sigprocmask</code>或者<code>man 2 sigprocmask</code>查询到的系统调用的函数声明形式。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="comment">/* Prototype for the glibc wrapper function */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">sigprocmask</span><span class="params">(<span class="type">int</span> how, <span class="type">const</span> <span class="type">sigset_t</span> *<span class="built_in">set</span>, <span class="type">sigset_t</span> *oldset)</span>;</span><br></pre></td></tr></table></figure></div><div class="tab-pane" id="tabname2-2"><p>【说明】使用<code>man 3 sigprocmask</code>查询到的库函数中的函数声明形式。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="comment">/* Prototype for the legacy system call (deprecated) */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">sigprocmask</span><span class="params">(<span class="type">int</span> how, <span class="type">const</span> <span class="type">old_kernel_sigset_t</span> *<span class="built_in">set</span>, <span class="type">old_kernel_sigset_t</span> *oldset)</span>;</span><br></pre></td></tr></table></figure>

<p>不过在<code>man</code>手册中有说明，该函数声明已经弃用，使用形式一即可，形式二仅作了解。</p></div></div></div>

<p><strong>【函数说明】</strong>该函数向信号掩码中添加或者删除信号，并设定对信号掩码内的信号的处理方式(阻塞或不阻塞)。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>how</code>：<code>int</code>类型，用于指定信号修改的方式，可能选择有三种。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 how 可能的取值 </summary>
              <div class='content'>
              <table>    <tr><td align="center" width=150px>SIG_BLOCK  </td><td align="left">将参数set所指向的信号集内的所有信号添加到进程的信号掩码中。</td></tr>    <tr><td align="center" width=150px>SIG_UNBLOCK</td><td align="left">将参数set指向的信号集内的所有信号从进程信号掩码中移除。</td></tr>    <tr><td align="center" width=150px>SIG_SETMASK</td><td align="left">进程信号掩码直接设置为参数set指向的信号集。</td></tr></table>
              </div>
            </details>

<ul>
<li><code>set</code>：<code>sigset_t</code>类型指针变量，将参数<code>set</code>指向的信号集内的所有信号添加到信号掩码中或者从信号掩码中移除；如果参数<code>set</code>为<code>NULL</code>，则表示无需对当前信号掩码作出改动。</li>
<li><code>oldset</code>：<code>sigset_t</code>类型指针变量，如果参数<code>oldset</code>不为<code>NULL</code>，在向信号掩码中添加新的信号之前，获取到进程当前的信号掩码，存放在<code>oldset</code>所指定的信号集中；如果为<code>NULL</code>则表示不获取当前的信号掩码。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败将返回<code>-1</code>，并设置<code>errno</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<div class="tabs" id="tabname3"><ul class="nav-tabs"><li class="tab active"><a href="#tabname3-1">添加信号到信号掩码</a></li><li class="tab"><a href="#tabname3-2">从信号掩码删除信号</a></li></ul><div class="tab-content"><div class="tab-pane active" id="tabname3-1"><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="type">sigset_t</span> sig_set;      <span class="comment">/* 定义信号集 */</span></span><br><span class="line">sigemptyset(&amp;sig_set); <span class="comment">/* 将信号集初始化为空 */</span></span><br><span class="line">sigaddset(&amp;sig_set, SIGINT);<span class="comment">/* 向信号集中添加SIGINT信号 */</span></span><br><span class="line">ret = sigprocmask(SIG_BLOCK, &amp;sig_set, <span class="literal">NULL</span>); <span class="comment">/* 向进程的信号掩码中添加信号 */</span></span><br><span class="line"><span class="keyword">if</span> (ret == <span class="number">-1</span>)</span><br><span class="line">&#123;</span><br><span class="line">	perror(<span class="string">&quot;sigprocmask error&quot;</span>);</span><br><span class="line">	<span class="built_in">exit</span>(<span class="number">-1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><div class="tab-pane" id="tabname3-2"><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line"><span class="type">sigset_t</span> sig_set; <span class="comment">/* 定义信号集 */</span></span><br><span class="line">sigemptyset(&amp;sig_set); <span class="comment">/* 将信号集初始化为空 */</span></span><br><span class="line">sigaddset(&amp;sig_set, SIGINT);<span class="comment">/* 向信号集中添加SIGINT信号 */</span></span><br><span class="line">ret = sigprocmask((SIG_UNBLOCK, &amp;sig_set, <span class="literal">NULL</span>); <span class="comment">/* 向进程的信号掩码中删除信号 */</span></span><br><span class="line"><span class="keyword">if</span> (ret == <span class="number">-1</span>)</span><br><span class="line">&#123;</span><br><span class="line">	perror(<span class="string">&quot;sigprocmask error&quot;</span>);</span><br><span class="line">	<span class="built_in">exit</span>(<span class="number">-1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div></div></div>

<p><strong>【注意事项】</strong><code>none</code></p>
<h4 id="3-2-2-使用实例"><a href="#3-2-2-使用实例" class="headerlink" title="3.2.2 使用实例"></a><font size=3>3.2.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* alarm sleep*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* sigaction */</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigactionHandle</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">1</span>;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">sigaction</span> <span class="title">act</span>;</span><span class="comment">/* 定义一个处理信号行为的结构体变量 */</span></span><br><span class="line">	<span class="type">sigset_t</span> <span class="built_in">set</span>;<span class="comment">/* 定义一个信号集变量 */</span></span><br><span class="line">	</span><br><span class="line">	<span class="comment">/* 1.设置捕捉信号 */</span></span><br><span class="line">	act.sa_handler = sigactionHandle;  <span class="comment">/* 指定信号处理函数 */</span></span><br><span class="line">	act.sa_flags = <span class="number">0</span>;                  <span class="comment">/* sa_flags指定了一组标志，这些标志用于控制信号的处理过程 */</span></span><br><span class="line">	sigemptyset(&amp;act.sa_mask);         <span class="comment">/* 将信号集初始化为空 */</span></span><br><span class="line">	sigaction(SIGINT, &amp;act, <span class="literal">NULL</span>);     <span class="comment">/* 捕捉信号 */</span></span><br><span class="line">	<span class="comment">/* 2.信号集清空 */</span></span><br><span class="line">	sigemptyset(&amp;<span class="built_in">set</span>);</span><br><span class="line">	<span class="comment">/* 3.向信号集添加信号 */</span></span><br><span class="line">	sigaddset(&amp;<span class="built_in">set</span>, SIGINT);</span><br><span class="line">	<span class="comment">/* 4.设置信号处理方式 */</span></span><br><span class="line">	sigprocmask(SIG_BLOCK,&amp;<span class="built_in">set</span>,<span class="literal">NULL</span>);</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)<span class="comment">/* 先为阻塞，5s后设置为不阻塞 */</span></span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;i = %d\n&quot;</span>,i);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">    sigprocmask(SIG_UNBLOCK, &amp;<span class="built_in">set</span>, <span class="literal">NULL</span>);<span class="comment">/* SIG_UNBLOCK： 从信号屏蔽字中删除参数set中的信号 */</span></span><br><span class="line">	</span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;i = %d\n&quot;</span>, i++);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigactionHandle</span><span class="params">(<span class="type">int</span> sig)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Get sig = %d[%d times]\n&quot;</span>, sig, ++count);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">i = 0</span><br><span class="line">i = 1</span><br><span class="line">^Ci = 2</span><br><span class="line">^Ci = 3</span><br><span class="line">^Ci = 4</span><br><span class="line">Get sig = 2[1 times]</span><br><span class="line">i = 5</span><br><span class="line">i = 6</span><br><span class="line">^CGet sig = 2[2 times]</span><br><span class="line">i = 7</span><br><span class="line">^CGet sig = 2[3 times]</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">后边的省略  ... ...</span></span><br></pre></td></tr></table></figure><p>我们会发现，在<code>i</code>不大于<code>4</code>的时候，按下<code>Ctrl+c</code>按键并没有效果，这是因为我们在这段时间阻塞了信号，当<code>i&gt;4</code>的时候，循环结束了，这个时候之前收到的信号立刻执行一次信号处理函数，即便我们按下多次，也只捕获了一次，之后信号被从信号掩码中移除，后边就可以正常接收信号了。</p>
              </div>
            </details>

<h3 id="3-3-获取处于阻塞状态的信号"><a href="#3-3-获取处于阻塞状态的信号" class="headerlink" title="3.3 获取处于阻塞状态的信号"></a><font size=3>3.3 获取处于阻塞状态的信号</font></h3><h4 id="3-3-1-sigpending"><a href="#3-3-1-sigpending" class="headerlink" title="3.3.1 sigpending() "></a><font size=3>3.3.1 sigpending() </font></h4><h5 id="3-3-1-1-函数说明"><a href="#3-3-1-1-函数说明" class="headerlink" title="3.3.1.1 函数说明"></a><font size=3>3.3.1.1 函数说明</font></h5><p>在<code>linux</code>下可以使用<code>man sigpending </code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">sigpending</span><span class="params">(<span class="type">sigset_t</span> *<span class="built_in">set</span>)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数可以获取进程中处于等待的信号也就是处于信号未决状态的信号，也可以说是可以获取进程的信号掩码（信号屏蔽字）。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>set</code>：<code>sigset_t</code>类型，处于等待状态的信号会存放在参数<code>set</code>所指向的信号集中。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败将返回<code>-1</code>，并设置<code>errno</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">sigset_t</span> sig_set;</span><br><span class="line">sigemptyset(&amp;sig_set);</span><br><span class="line"><span class="comment">// ......</span></span><br><span class="line">sigpending(sig_set);</span><br><span class="line"><span class="comment">/* 判断SIGINT信号是否处于等待状态 */</span> </span><br><span class="line"><span class="keyword">if</span> (sigismember(&amp;sig_set, SIGINT) == <span class="number">1</span>)</span><br><span class="line">    ... ...</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h5 id="3-3-1-2-使用实例"><a href="#3-3-1-2-使用实例" class="headerlink" title="3.3.1.2 使用实例"></a><font size=3>3.3.1.2 使用实例</font></h5><p>暂无。</p>
<h1 id="六、阻塞进程来等待信号"><a href="#六、阻塞进程来等待信号" class="headerlink" title="六、阻塞进程来等待信号"></a><font size=3>六、阻塞进程来等待信号</font></h1><h2 id="1-pause-函数"><a href="#1-pause-函数" class="headerlink" title="1. pause() 函数"></a><font size=3>1. pause() 函数</font></h2><h3 id="1-1-函数说明-2"><a href="#1-1-函数说明-2" class="headerlink" title="1.1 函数说明"></a><font size=3>1.1 函数说明</font></h3><p>在<code>linux</code>下可以使用<code>man 2 pause </code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">pause</span><span class="params">(<span class="type">void</span>)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数用可以使得进程暂停运行、进入休眠状态，直到进程捕获到一个信号为止。</p>
<p><strong>【函数参数】</strong><code>none</code></p>
<p><strong>【返回值】</strong><code>int</code>类型，只有执行了信号处理函数并从其返回时，<code>pause()</code>才返回，在这种情况，<code>pause()</code>返回<code>-1</code>，并且将<code>errno</code>设置为<code>EINTR</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line">pause();</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong></p>
<p>（1）如果信号的默认处理动作是终止进程，则进程终止，pause函数就没有机会返回了。</p>
<p>（2）如果信号的默认处理动作是忽略，进程继续处于挂起状态，<code>pause</code>函数不返回。</p>
<p>（3）如果信号的处理动作是捕捉，则调用完信号处理函数之后，<code>pause</code>返回<code>-1</code>。</p>
<p>（4）<code>pause</code>收到的信号如果被屏蔽，那么<code>pause</code>就不能被唤醒 。</p>
<h3 id="1-2-使用实例-1"><a href="#1-2-使用实例-1" class="headerlink" title="1.2 使用实例"></a><font size=3>1.2 使用实例</font></h3><p>这里是一个<code>pause</code>的基本使用实例。</p>
<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep pause */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* signal */</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="title function_">void</span> <span class="params">(*<span class="type">sighandler_t</span>)</span><span class="params">(<span class="type">int</span>)</span>;</span><br><span class="line"><span class="type">sighandler_t</span> oldact;</span><br><span class="line"><span class="type">void</span> <span class="title function_">sigintHandle</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> ret = <span class="number">0</span>;</span><br><span class="line">	oldact = signal(SIGINT, sigintHandle);</span><br><span class="line">	<span class="comment">/* 阻塞进程 */</span></span><br><span class="line">	ret = pause();<span class="comment">/* 被中断后才会继续向下执行 */</span></span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;After pause!ret=%d\n&quot;</span>, ret);</span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;Please Enter: Ctrl+c \n&quot;</span>);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigintHandle</span><span class="params">(<span class="type">int</span> sig)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;I catch the SIGINT![%d times] \n&quot;</span>, ++count);</span><br><span class="line">	signal(SIGINT, oldact);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，就会发现程序一直阻塞，直到我们按下<code>Ctrl+c</code>，捕获到信号后，程序才开始运行，之后终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">^CI catch the SIGINT![1 times] </span><br><span class="line">After pause!ret=-1</span><br><span class="line">Please Enter: Ctrl+c </span><br><span class="line">Please Enter: Ctrl+c </span><br><span class="line">^C</span><br></pre></td></tr></table></figure><p>程序开始运行后吗，再按一次<code>Ctrl+c</code>，程序便会正常终止了，而这个时候，<code>pause()</code>后边的语句不再执行，<code>pause</code>根本就没有进行返回，程序就结束了，这是因为<code>Ctrl+c</code>后来被改回了系统默认操作，也就是直接终止进程，根本不会给<code>pause</code>返回的机会。</p>
              </div>
            </details>

<h3 id="1-3-信号驱动任务"><a href="#1-3-信号驱动任务" class="headerlink" title="1.3 信号驱动任务"></a><font size=3>1.3 信号驱动任务</font></h3><p>这个例子其实是为了给下边的另一个阻塞进程等待信号的函数做铺垫。</p>
<details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* alarm sleep*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* sigaction */</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigactionHandle</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">mytask</span><span class="params">(<span class="type">void</span>)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">sigaction</span> <span class="title">act</span>;</span> <span class="comment">/* 定义一个处理信号行为的结构体变量 */</span></span><br><span class="line">	<span class="type">sigset_t</span> <span class="built_in">set</span>;         <span class="comment">/* 定义一个信号集变量 */</span></span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 1.捕获信号 */</span></span><br><span class="line">	<span class="comment">/* 1.1初始化处理信号行为的结构体变量 */</span></span><br><span class="line">	act.sa_handler = sigactionHandle;  <span class="comment">/* 指定信号处理函数 */</span></span><br><span class="line">	act.sa_flags = <span class="number">0</span>;                  <span class="comment">/* a_flags指定了一组标志，这些标志用于控制信号的处理过程 */</span></span><br><span class="line">	sigemptyset(&amp;act.sa_mask);         <span class="comment">/* 将信号集初始化为空 */</span></span><br><span class="line">	<span class="comment">/* 1.2设置捕捉信号 */</span></span><br><span class="line">	sigaction(SIGINT, &amp;act, <span class="literal">NULL</span>);     <span class="comment">/* Ctrl + c 发送该信号 */</span></span><br><span class="line">	sigaction(SIGHUP, &amp;act, <span class="literal">NULL</span>);     <span class="comment">/* kill -1 &lt;PID&gt; 发送该信号*/</span></span><br><span class="line">	<span class="comment">/* 2.信号阻塞设置 */</span></span><br><span class="line">	sigemptyset(&amp;<span class="built_in">set</span>);     <span class="comment">/* 信号集清空 */</span></span><br><span class="line">	sigaddset(&amp;<span class="built_in">set</span>,SIGHUP);<span class="comment">/* 向信号集添加信号 */</span></span><br><span class="line">	sigaddset(&amp;<span class="built_in">set</span>,SIGINT);<span class="comment">/* 向信号集添加信号 */</span></span><br><span class="line">	<span class="comment">/* 阻塞进程 */</span></span><br><span class="line">	pause();</span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 以下连续发两次信号操作，任务只会执行一次，但是信号处理函数会处正常处理两次 */</span></span><br><span class="line">		<span class="comment">/* 若不屏蔽信号，则在任务执行期间的有信号到来的话，任务函数会被直接打断 */</span></span><br><span class="line">		sigprocmask(SIG_BLOCK, &amp;<span class="built_in">set</span>, <span class="literal">NULL</span>);  <span class="comment">/* 屏蔽信号，以保证任务函数执行时不会被打断 */</span></span><br><span class="line">		mytask();<span class="comment">/* 执行任务期间所获取的信号不会被pause接收，在到pause前就会处理掉了 */</span></span><br><span class="line">		sigprocmask(SIG_UNBLOCK, &amp;<span class="built_in">set</span>, <span class="literal">NULL</span>);<span class="comment">/* 取消屏蔽 */</span></span><br><span class="line">		pause();</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigactionHandle</span><span class="params">(<span class="type">int</span> sig)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;I catch the signal [%d] %d times!\n&quot;</span>, sig, ++count);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">mytask</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">1</span>;</span><br><span class="line">	count++;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;My task start![%d times]\n&quot;</span>, count);</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">1</span>; i &lt; <span class="number">4</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;i = %d\n&quot;</span>, i);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;My task end![%d times]\n\n&quot;</span>, count);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，就会发现程序一直阻塞，直到我们按下<code>Ctrl+c</code>，捕获到信号后，程序才开始运行，之后我们在程序执行期间多按几次<code>Ctrl+c</code>按键，最后按<code>ctrl+\</code>退出进程，然后我们就会得到以下信息：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">^CI catch the signal [2] 1 times!</span><br><span class="line">My task start![1 times]</span><br><span class="line">i = 1</span><br><span class="line">i = 2</span><br><span class="line">^Ci = 3</span><br><span class="line">My task end![1 times]</span><br><span class="line"></span><br><span class="line">I catch the signal [2] 2 times!</span><br><span class="line">^CI catch the signal [2] 3 times!</span><br><span class="line">My task start![2 times]</span><br><span class="line">i = 1</span><br><span class="line">i = 2</span><br><span class="line">i = 3</span><br><span class="line">^CMy task end![2 times]</span><br><span class="line"></span><br><span class="line">I catch the signal [2] 4 times!</span><br><span class="line">^\退出 (核心已转储)</span><br></pre></td></tr></table></figure><p>观察输出信息，我们发现，我们一共按下<code>Ctrl+c</code>组合键四次，并且自定义的信号处理函数也成功捕获并执行了四次，但是我们的任务函数仅仅是执行了两次，这是为什么呢？我们来分析一下，当我们在执行任务函数的过程中，时间长达<code>3s</code>，这段时间内我们按下<code>Ctrl+c</code>组合键，这个时候由于信号是被屏蔽的，所以任务函数并不会被打断，任务函数结束后，解除了信号的屏蔽，这个时候会直接进入我们自定义的信号处理函数，执行信号处理函数，处理完毕后，这个信号就没有了，所以后边的<code>pause</code>函数并没有接收到该信号，所以会一直停留在<code>pause</code>处继续等待信号的到来，才会继续回到循环开始，再执行一次任务函数。</p>
              </div>
            </details>

<h2 id="2-sigsuspend-函数"><a href="#2-sigsuspend-函数" class="headerlink" title="2. sigsuspend() 函数"></a><font size=3>2. sigsuspend() 函数</font></h2><p>上边的<code>pause()</code>函数的信号驱动任务例子中，信号会被提前处理，导致<code>pause()</code>函数接收不到信号，想要解决这个问题，就需要将恢复信号掩码和<code>pause()</code>挂起进程这两个动作封装成一个原子操作，这样信号处理函数便无法在恢复信号掩码后直接执行了，这样信号就会被<code>pause()</code>接收到了。</p>
<h3 id="2-1-函数说明-3"><a href="#2-1-函数说明-3" class="headerlink" title="2.1 函数说明"></a><font size=3>2.1 函数说明</font></h3><p>在<code>linux</code>下可以使用<code>man 2 sigsuspend</code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">sigsuspend</span><span class="params">(<span class="type">const</span> <span class="type">sigset_t</span> *mask)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数会将参数<code>mask</code>所指向的信号集替换进程的信号掩码，也就是将进程的信号掩码设置为参数<code>mask</code>所指向的信号集，然后挂起进程，如果捕捉到一个信号并从信号处理函数返回，<code>sigsuspend()</code>返回，并将进程的信号掩码恢复成调用前的值；如果捕获的信号是<code>mask</code>信号集中的成员，将不会唤醒、会继续挂起，直到有非<code>mask</code>信号集中成员信号的到来。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>mask</code>：<code>sigset_t</code>类型指针变量，指向一个已经初始化过的信号集。</li>
</ul>
<p><strong>【返回值】</strong><code>int</code>类型，始终返回<code>-1</code>，并设置<code>errno</code>来指示错误（通常为<code>EINTR</code>），表示被信号所中断。如果调用失败，将<code>errno</code>设置为<code>EFAULT</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="type">sigset_t</span> set_mask;</span><br><span class="line">sigsuspend(&amp;set_mask);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong>调用<code>sigsuspend()</code>就等价于以不可中断的方式执行以下操作：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sigprocmask(SIG_SETMASK, &amp;mask, &amp;old_mask); </span><br><span class="line">pause(); </span><br><span class="line">sigprocmask(SIG_SETMASK, &amp;old_mask, <span class="literal">NULL</span>);</span><br></pre></td></tr></table></figure>

<h3 id="2-2-使用实例-2"><a href="#2-2-使用实例-2" class="headerlink" title="2.2 使用实例"></a><font size=3>2.2 使用实例</font></h3><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <figure class="highlight c"><figcaption><span>test.c</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* alarm sleep*/</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* sigaction */</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigactionHandle</span><span class="params">(<span class="type">int</span> sig)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">mytask</span><span class="params">(<span class="type">void</span>)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">sigaction</span> <span class="title">act</span>;</span>   <span class="comment">/* 定义一个处理信号行为的结构体变量 */</span></span><br><span class="line">	<span class="type">sigset_t</span> <span class="built_in">set</span>, set_mask; <span class="comment">/* 定义两个信号集变量 */</span></span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 1.捕获信号 */</span></span><br><span class="line">	<span class="comment">/* 1.1初始化处理信号行为的结构体变量 */</span></span><br><span class="line">	act.sa_handler = sigactionHandle;  <span class="comment">/* 指定信号处理函数 */</span></span><br><span class="line">	act.sa_flags = <span class="number">0</span>;                  <span class="comment">/* a_flags指定了一组标志，这些标志用于控制信号的处理过程 */</span></span><br><span class="line">	sigemptyset(&amp;act.sa_mask);         <span class="comment">/* 将信号集初始化为空 */</span></span><br><span class="line">	<span class="comment">/* 1.2设置捕捉信号 */</span></span><br><span class="line">	sigaction(SIGINT, &amp;act, <span class="literal">NULL</span>);     <span class="comment">/* Ctrl + c 发送该信号 */</span></span><br><span class="line">	sigaction(SIGHUP, &amp;act, <span class="literal">NULL</span>);     <span class="comment">/* kill -1 &lt;PID&gt; 发送该信号*/</span></span><br><span class="line">	<span class="comment">/* 2.信号阻塞设置 */</span></span><br><span class="line">	sigemptyset(&amp;<span class="built_in">set</span>);     <span class="comment">/* 信号集清空 */</span></span><br><span class="line">	sigemptyset(&amp;set_mask);<span class="comment">/* 信号集清空 */</span></span><br><span class="line">	sigaddset(&amp;<span class="built_in">set</span>,SIGHUP);<span class="comment">/* 向信号集添加信号 */</span></span><br><span class="line">	sigaddset(&amp;<span class="built_in">set</span>,SIGINT);<span class="comment">/* 向信号集添加信号 */</span></span><br><span class="line">	<span class="comment">/* 阻塞进程 */</span></span><br><span class="line">	pause();</span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="comment">/* 屏蔽信号，以保证任务函数执行时不会被打断 */</span></span><br><span class="line">		sigprocmask(SIG_BLOCK, &amp;<span class="built_in">set</span>, <span class="literal">NULL</span>);</span><br><span class="line">		mytask();</span><br><span class="line">		sigsuspend(&amp;set_mask);<span class="comment">/* set_mask 为空，意思是不屏蔽信号，这样在任务函数执行期间收到的信号会使这里返回 */</span></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigactionHandle</span><span class="params">(<span class="type">int</span> sig)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;I catch the signal [%d] %d times!\n&quot;</span>, sig, ++count);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">mytask</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">	count++;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;My task start![%d times]\n&quot;</span>, count);</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">1</span>; i &lt; <span class="number">4</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;This is task function![i = %d]\n&quot;</span>, i);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;My task end![%d times]\n&quot;</span>, count);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">gcc test.c -Wall # 生成可执行文件 a.out </span><br><span class="line">./a.out # 执行可执行程序</span><br></pre></td></tr></table></figure><p>然后，就会发现程序一直阻塞，直到我们按下<code>Ctrl+c</code>，捕获到信号后，程序才开始运行，之后我们在程序执行期间多按几次<code>Ctrl+c</code>按键，最后按<code>ctrl+\</code>退出进程，然后我们就会得到以下信息：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">^CI catch the signal [2] 1 times!</span><br><span class="line">My task start![1 times]</span><br><span class="line">This is task function![i = 1]</span><br><span class="line">^CThis is task function![i = 2]</span><br><span class="line">^CThis is task function![i = 3]</span><br><span class="line">My task end![1 times]</span><br><span class="line">I catch the signal [2] 2 times!</span><br><span class="line">My task start![2 times]</span><br><span class="line">This is task function![i = 1]</span><br><span class="line">This is task function![i = 2]</span><br><span class="line">This is task function![i = 3]</span><br><span class="line">My task end![2 times]</span><br><span class="line">^\退出 (核心已转储)</span><br></pre></td></tr></table></figure><p>可以看到，在任务函数执行期间，发出的信号在任务函数执行完毕后被捕获，并且返回，使任务函数再次执行。这样，在任务函数执行期间到来的信号就可以使任务函数再运行一次了，但是任务函数运行期间，收到多个相同信号，信号就相当于只被捕获了一次。</p>
              </div>
            </details>

<h1 id="七、实时信号"><a href="#七、实时信号" class="headerlink" title="七、实时信号"></a><font size=3>七、实时信号</font></h1><h2 id="1-实时信号的优势"><a href="#1-实时信号的优势" class="headerlink" title="1. 实时信号的优势"></a><font size=3>1. 实时信号的优势</font></h2><p>如果进程当前正在执行信号处理函数，在处理信号期间接收到了新的信号，且该信号是信号掩码中的成员，那么内核会将其阻塞，将该信号添加到进程的等待信号集（等待被处理，处于等待状态的信号）中，为了确定进程中处于等待状态的是哪些信号，可以使用<code>sigpending()</code>函数获取。</p>
<p>等待信号集只是一个掩码，<strong>仅表明一个信号是否发生，而不能表示其发生的次数</strong>。意思就是，如果一个同一个信号在阻塞状态下产生了多次，那么会将该信号记录在等待信号集中，并在之后仅传递一次（仅当做发生了一次），这个情况上边其实我们有遇到过就是在<code>sigsuspend</code>中遇到过，只是发生在任务处理函数中，不过这与发生在信号处理函数中是一样的，<strong>在执行不可被打断的操作时期间来的信号都只会被记录一次，后期也只会被处理一次</strong>，就是这是标准信号，也就是非实时信号的缺点之一。</p>
<p>相对于标准信号，实时信号有如下优势：</p>
<p>（1）实时信号的信号可应用于用户自定义的信号数量较多，标准信号仅提供了两个信号<code>SIGUSR1</code>和<code>SIGUSR2</code>用于应用程序自定义使用。</p>
<p>（2）内核对于实时信号所采取的是<strong>队列化管理</strong>。如果将某一实时信号多次发送给另一个进程，那么将会多次传递此信号。对于某一标准信号正在等待某一进程，而此时即使再次向该进程发送此信号，信号也只会传递一次。</p>
<p>（3）当发送一个实时信号时，我们可以为信号指定伴随数据（一个整形数据或者指针值），然后接收信号的进程就可以在它的信号处理函数中获取这些数据。</p>
<p>（4）不同实时信号的传递顺序得到保障。如果有多个不同的实时信号处于等待状态，那么将率先传递具有最小编号的信号。也就是说，信号的编号越小，其优先级越高，如果是同一类型的多个信号在排队，那么信号（以及伴随数据）的传递顺序与信号发送来时的顺序保持一致。</p>
<h2 id="2-使用实时信号"><a href="#2-使用实时信号" class="headerlink" title="2. 使用实时信号"></a><font size=3>2. 使用实时信号</font></h2><p><code>Linux</code>内核定义了<code>31</code>个不同的实时信号，信号编号范围为<code>34~64</code>，使用<code>SIGRTMIN</code>表示编号最小的实时信号，使用<code>SIGRTMAX</code>表示编号最大的实时信号，其它信号编号可使用这两个宏加上一个整数或减去一个整数。</p>
<p>使用实时信号的过程中，需要注意的有以下两点：</p>
<p>（1）发送进程使用<code>sigqueue()</code>系统调用向另一个进程发送实时信号以及伴随数据。</p>
<p>（2）接收实时信号的进程要为该信号建立一个信号处理函数，为了更便于我们的操作，我们应该选择使用<code>sigaction</code>函数为信号建立处理函数，并加入<code>SA_SIGINFO</code>，这样信号处理函数才能够接收到实时信号以及伴随数据，也就是要使用<code>sa_sigaction</code>指针指向的处理函数，而不是<code>sa_handler</code>，当然也允许使用<code>sa_handler</code>，但这样就无法获取到实时信号的伴随数据了。</p>
<h3 id="2-1-sigqueue-函数"><a href="#2-1-sigqueue-函数" class="headerlink" title="2.1 sigqueue() 函数"></a><font size=3>2.1 sigqueue() 函数</font></h3><h4 id="2-1-1-函数说明"><a href="#2-1-1-函数说明" class="headerlink" title="2.1.1 函数说明"></a><font size=3>2.1.1 函数说明</font></h4><p>在<code>linux</code>下可以使用<code>man 3 sigqueue </code>命令查看该函数的帮助手册。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 函数声明 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">sigqueue</span><span class="params">(<span class="type">pid_t</span> pid, <span class="type">int</span> sig, <span class="type">const</span> <span class="keyword">union</span> sigval value)</span>;</span><br></pre></td></tr></table></figure>

<p><strong>【函数说明】</strong>该函数是一个发送信号的系统调用，主要是针对实时信号（当然也支持标准信号），支持信号带有数据，与函数<code>sigaction()</code>配合使用。</p>
<p><strong>【函数参数】</strong></p>
<ul>
<li><code>pid</code>：<code>pid_t</code>类型，指定接收信号的进程对应的<code>pid</code>，后续会将信号发送给该进程。</li>
<li><code>sig</code>：<code>int</code>类型，表示需要发送的信号。与<code>kill()</code>函数一样，也可将参数<code>sig</code>设置为0，用于检查参数<code>pid</code>所指定的进程是否存在。</li>
<li><code>value</code>：<code>union sigval</code>类型的共用体，它指定了信号的伴随数据。</li>
</ul>
<details class="folding-tag" blue><summary> 点击查看 union sigval 成员 </summary>
              <div class='content'>
              <p>在使用<code>man 3 sigqueue </code>查看使用手册的时候，下边有这个共用体的介绍。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">union</span> <span class="title">sigval</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">	<span class="type">int</span>   sival_int;</span><br><span class="line">	<span class="type">void</span> *sival_ptr;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
              </div>
            </details>

<p><strong>【返回值】</strong><code>int</code>类型，成功返回<code>0</code>，失败返回<code>-1</code>，并设置<code>errno</code>。</p>
<p><strong>【使用格式】</strong>一般情况下基本使用格式如下：</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 需要包含的头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 至少应该有的语句 */</span></span><br><span class="line"><span class="class"><span class="keyword">union</span> <span class="title">sigval</span> <span class="title">sig_val</span>;</span></span><br><span class="line">sigqueue(pid, sig, sig_val);</span><br></pre></td></tr></table></figure>

<p><strong>【注意事项】</strong><code>none</code></p>
<h4 id="2-1-2-使用实例"><a href="#2-1-2-使用实例" class="headerlink" title="2.1.2 使用实例"></a><font size=3>2.1.2 使用实例</font></h4><details class="folding-tag" blue><summary> 点击查看实例 </summary>
              <div class='content'>
              <div class="tabs" id="tabname4"><ul class="nav-tabs"><li class="tab active"><a href="#tabname4-1">signalSend.c</a></li><li class="tab"><a href="#tabname4-2">signalReceive.c</a></li><li class="tab"><a href="#tabname4-3">Makefile</a></li></ul><div class="tab-content"><div class="tab-pane active" id="tabname4-1"><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror getchar */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span> <span class="comment">/* exit */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* sigqueue */</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">union</span> <span class="title">sigval</span> <span class="title">sig_val</span>;</span><span class="comment">/* 信号携带的数据的共用体变量 */</span></span><br><span class="line">	<span class="type">pid_t</span> pid;</span><br><span class="line">	<span class="type">int</span> sig;</span><br><span class="line">	<span class="type">char</span> ch;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;Please enter PID , signal:&quot;</span>);</span><br><span class="line">	<span class="built_in">scanf</span>(<span class="string">&quot;%d %d&quot;</span>, &amp;pid, &amp;sig);</span><br><span class="line">	<span class="keyword">while</span>((ch = getchar()) != EOF &amp;&amp; ch != <span class="string">&#x27;\n&#x27;</span>) ; <span class="comment">//清除缓冲区的内容</span></span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">0</span>; i &lt; <span class="number">3</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		sig_val.sival_int = i;</span><br><span class="line">		<span class="keyword">if</span> (sigqueue(pid, sig, sig_val) == <span class="number">-1</span>)</span><br><span class="line">		&#123;</span><br><span class="line">			perror(<span class="string">&quot;sigqueue error&quot;</span>);</span><br><span class="line">			<span class="built_in">exit</span>(<span class="number">-1</span>);</span><br><span class="line">		&#125;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;Send success[data=%d]!\n&quot;</span>, sig_val.sival_int);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></div><div class="tab-pane" id="tabname4-2"><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 头文件 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span>  <span class="comment">/* perror */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> <span class="comment">/* sleep getpid */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;signal.h&gt;</span> <span class="comment">/* sigaction */</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigactionHandle</span><span class="params">(<span class="type">int</span> sig, <span class="type">siginfo_t</span> *info, <span class="type">void</span> *context)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 主函数 */</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="class"><span class="keyword">struct</span> <span class="title">sigaction</span> <span class="title">act</span>;</span>   <span class="comment">/* 定义一个处理信号行为的结构体变量 */</span></span><br><span class="line"></span><br><span class="line">	<span class="comment">/* 1.捕获信号 */</span></span><br><span class="line">	<span class="comment">/* 1.1初始化处理信号行为的结构体变量 */</span></span><br><span class="line">	act.sa_sigaction = sigactionHandle;  <span class="comment">/* 指定信号处理函数 */</span></span><br><span class="line">	act.sa_flags = SA_SIGINFO;           <span class="comment">/* a_flags指定了一组标志，这些标志用于控制信号的处理过程 */</span></span><br><span class="line">	sigemptyset(&amp;act.sa_mask);           <span class="comment">/* 将信号集初始化为空 */</span></span><br><span class="line">	<span class="comment">/* 1.2设置捕捉信号 */</span></span><br><span class="line">	sigaction(SIGRTMIN, &amp;act, <span class="literal">NULL</span>);       <span class="comment">/* Ctrl + c 发送该信号 */</span></span><br><span class="line">	<span class="keyword">while</span>(<span class="number">1</span>)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;Please send signal.[PID=%d]\n&quot;</span>, getpid());</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigactionHandle</span><span class="params">(<span class="type">int</span> sig, <span class="type">siginfo_t</span> *info, <span class="type">void</span> *context)</span></span><br><span class="line">&#123;</span><br><span class="line">	<span class="type">static</span> <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">	<span class="type">int</span> i = <span class="number">0</span>;</span><br><span class="line">	<span class="class"><span class="keyword">union</span> <span class="title">sigval</span> <span class="title">sig_val</span> =</span> info-&gt;si_value;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;I catch the signal [%d] %d times,data=%d \n&quot;</span>, sig, ++count, sig_val.sival_int);</span><br><span class="line">	<span class="keyword">for</span>(i = <span class="number">1</span>; i &lt; <span class="number">7</span>; i++)</span><br><span class="line">	&#123;</span><br><span class="line">		<span class="built_in">printf</span>(<span class="string">&quot;sigactionHandle running![%d]\n&quot;</span>, i);</span><br><span class="line">		sleep(<span class="number">1</span>);</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="built_in">printf</span>(<span class="string">&quot;sigactionHandle end!\n&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></div><div class="tab-pane" id="tabname4-3"><figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">CC = gcc</span><br><span class="line"></span><br><span class="line">DEBUG = -g -O2 -Wall</span><br><span class="line">CFLAGS += <span class="variable">$(DEBUG)</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 所有.c文件去掉后缀</span></span><br><span class="line">TARGET_LIST = $&#123;patsubst %.c, %, $&#123;wildcard *.c&#125;&#125; </span><br><span class="line"></span><br><span class="line">all : <span class="variable">$(TARGET_LIST)</span></span><br><span class="line"></span><br><span class="line">%.o : %.c</span><br><span class="line">	<span class="variable">$(CC)</span> <span class="variable">$(CFLAGS)</span> -c <span class="variable">$&lt;</span> -o <span class="variable">$@</span></span><br><span class="line"></span><br><span class="line"><span class="meta"><span class="keyword">.PHONY</span>: all clean clean_o</span></span><br><span class="line">clean : clean_o</span><br><span class="line">	@rm -vf <span class="variable">$(TARGET_LIST)</span> </span><br><span class="line">	</span><br><span class="line">clean_o :</span><br><span class="line">	@rm -vf *.o</span><br></pre></td></tr></table></figure></div></div></div><p>在终端执行以下命令编译程序：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">make # 生成可执行文件</span><br><span class="line">./signalSend    # 在一个终端执行发送信号函数</span><br><span class="line">./signalReceive # 在另一个终端执行信号接收函数</span><br></pre></td></tr></table></figure><p>然后，终端会有以下信息显示：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">执行 ./signalSend 的终端</span></span><br><span class="line">hk@vm:/mnt/hgfs/Sharedfiles/temp$ ./signalSend</span><br><span class="line">Please enter PID , signal:30650 34</span><br><span class="line">Send success[data=0]!</span><br><span class="line">Send success[data=1]!</span><br><span class="line">Send success[data=2]!</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">执行 ./signalReceive 的终端</span></span><br><span class="line">hk@vm:~/2Sharedfiles/temp$ ./signalReceive</span><br><span class="line">Please send signal.[PID=30650]</span><br><span class="line">Please send signal.[PID=30650]</span><br><span class="line">I catch the signal [34] 1 times,data=0 </span><br><span class="line">sigactionHandle running![1]</span><br><span class="line">sigactionHandle running![2]</span><br><span class="line">sigactionHandle running![3]</span><br><span class="line">sigactionHandle running![4]</span><br><span class="line">sigactionHandle running![5]</span><br><span class="line">sigactionHandle running![6]</span><br><span class="line">sigactionHandle end!</span><br><span class="line">I catch the signal [34] 2 times,data=1 </span><br><span class="line">sigactionHandle running![1]</span><br><span class="line">sigactionHandle running![2]</span><br><span class="line">sigactionHandle running![3]</span><br><span class="line">sigactionHandle running![4]</span><br><span class="line">sigactionHandle running![5]</span><br><span class="line">sigactionHandle running![6]</span><br><span class="line">sigactionHandle end!</span><br><span class="line">I catch the signal [34] 3 times,data=2 </span><br><span class="line">sigactionHandle running![1]</span><br><span class="line">sigactionHandle running![2]</span><br><span class="line">sigactionHandle running![3]</span><br><span class="line">sigactionHandle running![4]</span><br><span class="line">sigactionHandle running![5]</span><br><span class="line">sigactionHandle running![6]</span><br><span class="line">sigactionHandle end!</span><br><span class="line">Please send signal.[PID=30650]</span><br></pre></td></tr></table></figure><p>会发现，发送的三次信号并未打断正在执行的信号处理函数，并且所有的信号都保留了下来。</p>
              </div>
            </details>

    </div>

    
    
    

    <footer class="post-footer">




    <div>
        
            <div style="text-align:center;color: #ccc;font-size:14px;">
            ----------本文结束
            <i class="fas fa-fan fa-spin" style="color: #FF1493; font-size: 1rem"></i>
            感谢您的阅读----------
            </div>
        
    </div>





  
  <div class="my_post_copyright"> 
    <p><span>文章标题:</span><a href="/post/8457f426.html">LV05-05-进程通信-03-信号</a></p>
    <p><span>文章作者:</span><a href="/" title="欢迎访问 《苏木》 的学习笔记">苏木</a></p>
    <p><span>发布时间:</span>2023年07月02日 - 21:52</p>
    <p><span>最后更新:</span>2025年06月14日 - 00:25</p>
    <p><span>原始链接:</span><a href="/post/8457f426.html" title="LV05-05-进程通信-03-信号">https://sumumm.github.io/post/8457f426.html</a></p>
    <p><span>许可协议:</span><i class="fab fa-creative-commons"></i> <a rel="license" href= "https://creativecommons.org/licenses/by-nc-nd/4.0/" target="_blank" title="Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)">署名-非商业性使用-禁止演绎 4.0 国际</a> 转载请保留原文链接及作者。</p>  
  </div>
  


          <div class="post-tags">
              <a href="/tags/LV05-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/" rel="tag"><i class="fa fa-tag"></i> LV05-操作系统</a>
          </div>

        

          <div class="post-nav">
            <div class="post-nav-item">
                <a href="/post/ecb2bcfe.html" rel="prev" title="LV05-05-进程通信-04-共享内存">
                  <i class="fa fa-angle-left"></i> LV05-05-进程通信-04-共享内存
                </a>
            </div>
            <div class="post-nav-item">
                <a href="/post/3873081f.html" rel="next" title="LV05-05-进程通信-02-管道">
                  LV05-05-进程通信-02-管道 <i class="fa fa-angle-right"></i>
                </a>
            </div>
          </div>
    </footer>
  </article>
</div>






</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">

  <div class="copyright">
    &copy; 2017 – 
    <span itemprop="copyrightYear">2025</span>
    <span class="with-love">
      <i class="fa fa-heart"></i>
    </span>
    <span class="author" itemprop="copyrightHolder">苏木</span>
  </div>
<div class="wordcount">
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-line"></i>
    </span>
      <span>站点总字数：</span>
    <span title="站点总字数">3.7m</span>
  </span>
  <span class="post-meta-item">
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
      <span>站点阅读时长 &asymp;</span>
    <span title="站点阅读时长">225:26</span>
  </span>
</div>




    <span id="sitetime"></span>
    <script defer language=javascript>
        function siteTime()
        {
            window.setTimeout("siteTime()", 1000);
            var seconds = 1000;
            var minutes = seconds * 60;
            var hours = minutes * 60;
            var days = hours * 24;
            var years = days * 365;
            var today = new Date();
            var todayYear = today.getFullYear();
            var todayMonth = today.getMonth()+1;
            var todayDate = today.getDate();
            var todayHour = today.getHours();
            var todayMinute = today.getMinutes();
            var todaySecond = today.getSeconds();
            /*==================================================
            Date.UTC() -- 返回date对象距世界标准时间(UTC)1970年1月1日午夜之间的毫秒数(时间戳)
            year        - 作为date对象的年份，为4位年份值
            month       - 0-11之间的整数，做为date对象的月份
            day         - 1-31之间的整数，做为date对象的天数
            hours       - 0(午夜24点)-23之间的整数，做为date对象的小时数
            minutes     - 0-59之间的整数，做为date对象的分钟数
            seconds     - 0-59之间的整数，做为date对象的秒数
            microseconds - 0-999之间的整数，做为date对象的毫秒数
            ==================================================*/
            var t1 = Date.UTC(2017, 
                              5, 
                              19, 
                              0, 
                              0, 
                              0); //北京时间
            var t2 = Date.UTC(todayYear,todayMonth,todayDate,todayHour,todayMinute,todaySecond);
            var diff = t2-t1;
            var diffYears = Math.floor(diff/years);
            var diffDays = Math.floor((diff/days)-diffYears*365);
            var diffHours = Math.floor((diff-(diffYears*365+diffDays)*days)/hours);
            var diffMinutes = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours)/minutes);
            var diffSeconds = Math.floor((diff-(diffYears*365+diffDays)*days-diffHours*hours-diffMinutes*minutes)/seconds);
            document.getElementById("sitetime").innerHTML="已在这里 "+diffYears+" 年 "+diffDays+" 天 "+diffHours+" 小时 "+diffMinutes+" 分钟 "+diffSeconds+" 秒";
        }
        siteTime();
    </script>



    </div>
  </footer>

  
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/next-theme-pjax/0.6.0/pjax.min.js" integrity="sha256-vxLn1tSKWD4dqbMRyv940UYw4sXgMtYcK6reefzZrao=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.umd.js" integrity="sha256-ytMJGN3toR+a84u7g7NuHm91VIR06Q41kMWDr2pq7Zo=" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/lozad.js/1.16.0/lozad.min.js" integrity="sha256-mOFREFhqmHeQbXpK2lp4nA3qooVgACfh88fpJftLBbc=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script><script src="/js/pjax.js"></script>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>




  <script src="/js/third-party/fancybox.js"></script>

  <script src="/js/third-party/pace.js"></script>


  




  

  <script class="next-config" data-name="enableMath" type="application/json">true</script><script class="next-config" data-name="mathjax" type="application/json">{"enable":true,"tags":"none","js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.js","integrity":"sha256-MASABpB4tYktI2Oitl4t+78w/lyA+D7b/s9GEP0JOGI="}}</script>
<script src="/js/third-party/math/mathjax.js"></script>


 
        <div id="click-show-text"
            data-mobile = false
            data-text = 富强,民主,文明,和谐,自由,平等,公正,法制,爱国,敬业,诚信,友善
            data-fontsize = 15px
            data-random= false>
        </div>
       

      
        <script async src=https://cdn.jsdelivr.net/npm/hexo-next-mouse-effect@latest/click/showText.js></script>
      

      
    




    <script async src="/js/fancybox_param.js"></script>





<!-- APlayer本体 -->



</body>
</html>
